1 #!/usr/bin/perl
2 # yargla - Yet Another Rapid Glue Last.fm App v0.02
3 # Glues together Audio::MPD and Audio::Scrobbler
4 # Reads current playing track from MPD daemon
5 # and submits it to your last.fm profile
6
7 # put yargla somewhere in your $PATH, chmod +x it
8 # install Audio::MPD, Audio::Scrobbler and Config::Tiny (and Readonly)
9 # with cpan -i or your distrib/os packages
10 # p5-Audio-MPD, p5-Audio-Scrobbler and p5-Config-Tiny are in OpenBSD ports
11
12 # i wrote this script because mpdscribble kept segfaulting on my boxes,
13 # scmpc has mad dependencies, and i like perl - the glue of the internet.
14
15 # the mandatory licence for each little piece of code - ISC licenced
16 #
17 # Copyright (c) 2008 Jasper Lievisse Adriaanse <jasper@humppa.nl>
18 # Copyright (c) 2007 Landry Breuil <gaston@gcu.info>
19 #
20 # Permission to use, copy, modify, and distribute this software for any
21 # purpose with or without fee is hereby granted, provided that the above
22 # copyright notice and this permission notice appear in all copies.
23 #
24 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
25 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
26 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
27 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
28 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
29 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
30 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 #
32 # TODO: daemonize on -d, log into file
33 # cache tracks and submit by batchs
34 #
35 # sample config file:
36 # ; MPD-host variables
37 # [mpd]
38 # host = localhost
39 # port = 6600
40 # ; Last.FM user variables
41 # [lastfm]
42 # user = foo
43 # password = secret
44 #
45
46 use Audio::MPD;
47 use Audio::Scrobbler;
48 use Config::Tiny;
49 use Getopt::Long;
50 use strict;
51
52 use vars qw($VERSION);
53 $VERSION = "0.02";
54
55 sub usage;
56
57 # parse cmdline options
58 my ($as_user, $as_pass, $mpd_host, $mpd_port) = ('', '', 'localhost', 6600);
59 my ($help, $verbose, $config, $config_fh);
60
61 GetOptions('verbose' => \$verbose,
62 'help' => \$help,
63 'file:s' => \$config,
64 'user:s' => \$as_user,
65 'password:s' => \$as_pass,
66 'mpd:s' => \$mpd_host,
67 'nport:i' => \$mpd_port);
68
69 if ($as_user eq '' || $as_pass eq '' || $help) {
70 usage() if (!defined($config));
71 }
72
73 # parse the configuration file
74 unless (!defined($config)) {
75 if (! -e $config) {
76 print "Configuration file $config not found.\n";
77 usage();
78 }
79 $config_fh = Config::Tiny->read("$config");
80 }
81
82 $mpd_host = $config_fh->{mpd}->{host};
83 $mpd_port = $config_fh->{mpd}->{port};
84 $as_user = $config_fh->{lastfm}->{user};
85 $as_pass = $config_fh->{lastfm}->{password};
86
87 # validate the configuration values
88 if ((!defined($mpd_host)) or ($mpd_host eq '')) {
89 die "No valid host found in $config\n";
90 } elsif ((!defined($mpd_port)) or ($mpd_port eq '')) {
91 die "No valid port found in $config\n";
92 } elsif ((!defined($as_user)) or ($as_user eq '')) {
93 die "No valid user found in $config\n";
94 } elsif ((!defined($as_pass)) or ($as_pass eq '')) {
95 die "No valid password found in $config\n";
96 }
97
98 # initialize handlers on both sides
99 print "Connecting to MPD on $mpd_host:$mpd_port\n";
100 my $mpd = Audio::MPD->new($mpd_host, $mpd_port) || die "Failed to connect to MPD";
101
102 my $as = Audio::Scrobbler->new( cfg => {
103 verbose => $verbose,
104 progname => 'mdc', # use mpdscribble id atm
105 progver => '0.2.12',
106 username => $as_user,
107 password => $as_pass} );
108
109 $as->handshake() || die "Failed to handshake() with Last.fm";
110
111 my $status = $mpd->status();
112
113 while(1)
114 {
115 my $curid = $status->songid();
116 my $cursong = $mpd->current();
117
118 my ($artist,$title,$album,$length) = ($cursong->artist,$cursong->title,$cursong->album,$cursong->time);
119 my @t = localtime();
120 my $datestr = sprintf('%04d-%02d-%02d %02d:%02d:%02d', $t[5] + 1900, $t[4] + 1, @t[3, 2, 1, 0]);
121
122 print "[$datestr] submitting $artist - $album - $title\n";
123
124 my $r = $as->submit( {title => "$title", artist => "$artist", album => "$album", 'length' => "$length"});
125
126 if (!$r)
127 {
128 print "error:".$as->err.", trying to re-handshake and re-submit in 5s...\n";
129 sleep 5;
130 $as->handshake();
131 $as->submit( {title => "$title", artist => "$artist", album => "$album", 'length' => "$length"});
132 }
133
134 while ($curid == $status->songid)
135 {
136 if ($status->state eq "play")
137 { sleep 10; }
138 else
139 { sleep 60; }
140 $status = $mpd->status();
141 }
142 }
143
144 sub usage
145 {
146 print "$0 v. $VERSION\n";
147 print "usage: $0 -v|--verbose -h|--help -f|--file [config] \n-u|--user [Last.fm user] -p|--password [Last.fm password] -m|--mpd [MPD host]\n-n|--nport [MPD port]\n\n";
148 print "-u and -p are mandatory, unless -f is specified\n";
149 print "-m and -n defaults to localhost:6600\n";
150 print "-h shows usage\n\n";
151 print "values provided in the file provided with -f, overrule command line flags\n";
152 exit;
153 }
154
155 # (c) 2007 - G.C.U.