New hack: mpd_random_playlist.c
[mpd-hacks.git] / impc.pl
blob5417851a7c47fe6de708e86692f0a0baf8729412
1 ############################################################################
2 # Commands:
3 # /mplay [title|filename|artist|album] <search arg>
4 # First arguments are optional, if left out, title is used.
6 # /madd [title|filename|artist|album] <search arg>
7 # /mremove [title|filename|artist|album] <search arg>
8 # /mload [title|filename|artist|album] <search arg>
9 # First arguments are optional, if left out, artist is used.
10 # If invoked without any arguments all files are added/removed to/from list.
12 # /madd will search for <search args> and add result to current playlist
13 # /mremove will search for <search args> and remove matches from current playlist
14 # /mload will search for <search args> and create a playlist with the found files.
15 # So if you want to listen to the artist FooBars you type /mload artist FooBars
17 # /mshow
18 # Prints Artist - Album - Title to active window
19 # Not that anyone will ever be interested in what song you are
20 # listening to, but what the heck.
22 # (Self explained)
23 # /mnext
24 # /mprev
25 # /mseek <percent>
26 # /mpause
27 # /mstop
28 # /mrandom [on/1|off/0]
29 # /mrepeat [on/1|off/0]
30 # /mvolume [percent]
31 # /mclear
32 # /mconnect
34 # Variables (settings) - set from irssi with /set
36 # mpd_show_state ON/OFF
37 # > - play
38 # || - pause
39 # [] - stop
40 # ? - wha?
41 # mpd_show_artist ON/OFF
42 # mpd_show_album ON/OFF
43 # mpd_show_title ON/OFF
44 # mpd_show_time ON/OFF
45 # mpd_show_percent ON/OFF
46 # mpd_show_volume ON/OFF
47 # mpd_show_mode ON/OFF
48 # r - repeat
49 # z - random
50 # mpd_autoreconnect ON/OFF
53 # Enjoy!
55 # Known bugs:
57 # Changelog:
59 # 2.1.3 - Corrected Audio::MPD constructor arguments
60 # 2.1.2 - Added /mremove
61 # 2.1.1 - Added mpd_show_volume and mpd_show_mode.
62 # Changed position-format from ##.#% to ##%
63 # Removed iconv-stuff
64 # 2.1.0 - Rewritten for Audio::MPD 0.19.1
65 # Added mpd_show_artist, mpd_show_album
66 # 2.0.5 - Removed some redudant code.
67 # Below only works with Audio::MPD 0.12.4 patched with Audio-MPD-0.12.4-safeconnect.patch
68 # (http://0xa0.org/stuff/Audio-MPD-0.12.4-safeconnect.patch)
69 # Added setting: mpd_autoreconnect
70 # Added /mconnect
71 # 2.0.4 - MPD seems to have moved back to Audio::MPD in 0.12.3 ...
72 # I'll leave it to the user to change these two lines of code
73 # back to MPD as in 2.0.3 if they happen to be using an older version
74 # of Audio::MPD (MPD).
75 # 2.0.3 - Audio::MPD seems to have moved to MPD, appropriate changes made.
76 # 2.0.2 - Missing ;
77 # 2.0.1 - Fixed a bug in /mplay where no results were played unless the
78 # first match were a track in the playlist.
79 # 2.0.0 - Total rewrite. Now uses Audio::MPD. Most things remain the same.
80 # /mremove was removed since it was very ugly and I found no nice way
81 # to implement it.
82 # mpd_show_artist was removed and is now a part of mpd_show_title.
83 # 1.3.4 - Just changed the hardcoded MPD_PORT and MPD_HOST to use the env-vars
84 # if set.
85 # 1.3.3 - Removed $data="OK" from get_playlistinfo since it caused ogg/flac
86 # files titles to not be displayed, as pointed out by jat in #mpd.
87 # 1.3.2 - Added utf8 to iso-8859-15 convertion. No more รถ here!
88 # 1.3.1 - if no tag, display filename, as pointed out by t0ffel. Thanks.
89 # added /minfo and /mclear
90 # 1.3.0 - remade big parts of the script. Added a /mvolume
91 # 1.2.1 - changed my email address to the evilninja.org domain.
92 # 1.2 - added /mload, /mremove, /madd - thus breaking the no-playlist-thing. :)
93 # 1.1 - added /mstop, /mrepeat and /mrandom
94 ############################################################################
95 use strict;
97 use Irssi;
98 use Irssi::Irc;
99 use Irssi::TextUI;
100 use Audio::MPD;
101 use Env qw(MPD_PORT MPD_HOST);
103 use vars qw($VERSION %IRSSI);
105 $VERSION = "2.1.2";
107 %IRSSI = (
108 author => 'bumby',
109 contact => 'bumbyn@gmail.com',
110 name => 'impc',
111 description => 'Irssi MPD control',
112 license => 'BSD',
113 changed => '2007/12/28'
116 ############################################################################
117 # Setups
119 our %MPD = ();
120 $MPD{'port'} = $ENV{'MPD_PORT'}?$ENV{'MPD_PORT'}:"6600";
121 $MPD{'host'} = $ENV{'MPD_HOST'}?$ENV{'MPD_HOST'}:"localhost";
122 $MPD{'timeout'} = "5";
124 our $mpd = new Audio::MPD(hostname =>$MPD{'host'}, port => $MPD{'port'});
126 our %STATE = ();
127 $STATE{'play'} = ' >';
128 $STATE{'pause'} = '||';
129 $STATE{'stop'} = '[]';
131 # to give impc a dedicated statusbar comment these two lines
132 #Irssi::command("statusbar window add mpdbar");
133 #Irssi::command("statusbar window enable mpdbar");
134 # and uncomment these
135 Irssi::command("statusbar dmpdbar placement top");
136 Irssi::command("statusbar dmpdbar position 0");
137 Irssi::command("statusbar dmpdbar enable");
138 Irssi::command("statusbar dmpdbar add mpdbar");
139 Irssi::command("statusbar dmpdbar visible active");
141 Irssi::settings_add_bool('misc', 'mpd_show_state', '1');
142 Irssi::settings_add_bool('misc', 'mpd_show_artist', '1');
143 Irssi::settings_add_bool('misc', 'mpd_show_album', '0');
144 Irssi::settings_add_bool('misc', 'mpd_show_title', '1');
145 Irssi::settings_add_bool('misc', 'mpd_show_time', '1');
146 Irssi::settings_add_bool('misc', 'mpd_show_percent', '1');
147 Irssi::settings_add_bool('misc', 'mpd_show_volume', '0');
148 Irssi::settings_add_bool('misc', 'mpd_show_mode', '0');
149 Irssi::settings_add_bool('misc', 'mpd_autoreconnect', '0');
150 ############################################################################
152 ############################################################################
153 # irssi-bound commands
155 sub play {
156 my ($args, $server, $witem) = @_;
157 my @a = split(/ /, $args);
158 my $type = lc shift @a;
159 my $name = "";
160 foreach my $element (@a){
161 $name.=$element." ";
163 $name=~s/\s+$//g;
165 if($type eq ""){
166 eval { $mpd->play(0); };
167 if($@) {
168 $MPD{'state'}="Error: $@";
169 Irssi::statusbar_items_redraw('mpdbar');
170 return;
172 return;
175 if($name eq ""){$name=$type}
177 $MPD{'state'}="Searching...";
178 Irssi::statusbar_items_redraw('mpdbar');
180 my @plylist;
182 eval { @plylist = $mpd->playlist->as_items; };
184 if($@) {
185 $MPD{'state'}="Error: $@";
186 Irssi::statusbar_items_redraw('mpdbar');
187 return;
190 my $tracknr = undef;
191 while( (my $track = shift @plylist) && not defined $tracknr) {
192 if($track->{$type} =~ /$name/i) {
193 eval { $mpd->play($track->{'pos'}); };
194 if($@) {
195 $MPD{'state'}="Error: $@";
196 Irssi::statusbar_items_redraw('mpdbar');
198 return;
203 sub remove {
204 my ($args, $server, $witem) = @_;
205 my @a = split(/ /, $args);
206 my $type = lc shift @a;
207 my $name = "";
208 foreach my $element (@a){
209 $name.=$element." ";
211 $name=~s/\s+$//g;
213 if($type eq ""){clear();return;}
214 if($name eq ""){$name=$type}
216 $MPD{'state'}="Searching...";
217 Irssi::statusbar_items_redraw('mpdbar');
219 my @plylist;
221 eval { @plylist = $mpd->playlist->as_items; };
223 if($@) {
224 $MPD{'state'}="Error: $@";
225 Irssi::statusbar_items_redraw('mpdbar');
226 return;
229 my $tracknr = undef;
230 while( (my $track = shift @plylist) && not defined $tracknr) {
231 if($track->{$type} =~ /$name/i) {
232 eval { $mpd->playlist->deleteid($track->{'id'}); };
233 if($@) {
234 $MPD{'state'}="Error: $@";
235 Irssi::statusbar_items_redraw('mpdbar');
241 sub add {
242 my ($args, $server, $witem) = @_;
243 my @a = split(/ /, $args);
244 my $argc = $#a;
245 my $type = shift @a;
246 my $name = "";
247 my @files;
249 foreach my $element (@a){
250 $name.=$element." ";
252 $name=~s/\s+$//g;
254 if($name eq ""){$name=$type;$type='artist';}
257 $MPD{'state'}="Searching...";
258 Irssi::statusbar_items_redraw('mpdbar');
260 if($argc < 0) {
261 eval { @files = $mpd->collection->all_items_simple; };
262 if($@) {
263 $MPD{'state'}="Error: $@";
264 Irssi::statusbar_items_redraw('mpdbar');
265 return;
267 } else {
268 if($type eq 'title') {
269 eval { @files = $mpd->collection->songs_with_title_partial($name); };
270 } elsif($type eq 'album') {
271 eval { @files = $mpd->collection->songs_from_album_partial($name); };
272 } else {
273 eval { @files = $mpd->collection->songs_by_artist_partial($name); };
276 if($@) {
277 $MPD{'state'}="Error: $@";
278 Irssi::statusbar_items_redraw('mpdbar');
279 return;
283 $MPD{'state'}="Adding...";
284 Irssi::statusbar_items_redraw('mpdbar');
286 eval { foreach(@files){$mpd->playlist->add($_->{'file'}) if exists $_->{'file'}} };
287 if($@) {
288 $MPD{'state'}="Error: $@";
289 Irssi::statusbar_items_redraw('mpdbar');
293 sub load {
294 my ($args, $server, $witem) = @_;
296 clear();
297 add($args, $server, $witem);
298 eval { $mpd->play(0); };
299 if($@) {
300 $MPD{'state'}="Error: $@";
301 Irssi::statusbar_items_redraw('mpdbar');
302 return;
306 sub seek {
307 my ($args, $server, $witem) = @_;
308 if($args<0 and $args>100){return;}
310 my $seektime = $MPD{'current'}->{'time'} * ($args/100);
311 $mpd->seek($seektime);
314 sub volume {
315 my ($args, $server, $witem) = @_;
316 unless($args){
317 Irssi::print("Current volume: ".$MPD{'status'}->{'volume'});
318 return;
320 if($args<0 and $args>100){return;}
321 $mpd->volume($args);
324 sub random {
325 my ($args, $server, $witem) = @_;
326 if($args=~/(1|on)/i){
327 $mpd->random(1);
328 }elsif($args=~/(0|off)/i){
329 $mpd->random(0);
330 }else{
331 $mpd->random;
335 sub repeat {
336 my ($args, $server, $witem) = @_;
337 if($args=~/(1|on)/i){
338 $mpd->repeat(1);
339 }elsif($args=~/(0|off)/i){
340 $mpd->repeat(0);
341 }else{
342 $mpd->repeat;
346 sub info {
347 Irssi::statusbar_items_redraw('mpdbar');
348 if($MPD{'current'}->{'title'}){
349 Irssi::active_win()->print( $MPD{'current'}->{'title'});
350 }else{
351 Irssi::active_win()->print( $MPD{'current'}->{'file'});
354 Irssi::active_win()->print( $MPD{'state'}." #".$MPD{'status'}->{'song'}."/".$MPD{'status'}->{'playlistlength'}.
355 " ".$MPD{'status'}->{'time'}->{'sofar'}." (".$MPD{'status'}->{'time'}->{'percent'}."%)");
356 my $repeat = $MPD{'status'}->{'repeat'}?"on":"off";
357 my $random = $MPD{'status'}->{'random'}?"on":"off";
358 Irssi::active_win()->print( "volume: ".$MPD{'status'}->{'volume'}."% repeat: ".$repeat.
359 " random: ".$random);
361 sub stop {
362 eval { $mpd->stop; };
363 if($@) {
364 $MPD{'state'}="Error: $@";
365 Irssi::statusbar_items_redraw('mpdbar');
366 return;
370 sub pause {
371 eval { $mpd->pause; };
372 if($@) {
373 $MPD{'state'}="Error: $@";
374 Irssi::statusbar_items_redraw('mpdbar');
377 sub next {
378 eval { $mpd->next; };
379 if($@) {
380 $MPD{'state'}="Error: $@";
381 Irssi::statusbar_items_redraw('mpdbar');
384 sub prev {
385 eval { $mpd->prev; };
386 if($@) {
387 $MPD{'state'}="Error: $@";
388 Irssi::statusbar_items_redraw('mpdbar');
391 sub clear {
392 eval { $mpd->playlist->clear; };
393 if($@) {
394 $MPD{'state'}="Error: $@";
395 Irssi::statusbar_items_redraw('mpdbar');
399 ############################################################################
400 # Setup the statusbar
402 sub mpdbar_setup {
403 my ($item, $get_size_only) = @_;
404 my $info = "";
406 return unless $MPD{'status'};
408 $info.=$MPD{'state'}." " if(Irssi::settings_get_bool('mpd_show_state'));
409 if($MPD{'current'}->{'title'}) {
410 $info.=$MPD{'current'}->{'artist'}." - " if(Irssi::settings_get_bool('mpd_show_artist'));
411 $info.=$MPD{'current'}->{'album'}." - " if(Irssi::settings_get_bool('mpd_show_album'));
412 $info.=$MPD{'current'}->{'title'}." " if(Irssi::settings_get_bool('mpd_show_title'));
413 $info=~s/( - )+$//;
414 } else {
415 $info.=$MPD{'current'}->{'file'}." ";
418 $info.= "(";
419 if(Irssi::settings_get_bool('mpd_show_time')) {
420 $info.= $MPD{'status'}->{'time'}->{'sofar'}."/".$MPD{'status'}->{'time'}->{'total'};
421 $info.= " ";
424 if(Irssi::settings_get_bool('mpd_show_percent')) {
425 $info.= int($MPD{'status'}->{'time'}->{'percent'}+0.5)."%";
426 $info.= " ";
429 if(Irssi::settings_get_bool('mpd_show_volume')) {
430 $info.= "Volume: ".$MPD{'status'}->{'volume'}."%";
431 $info.= " ";
434 if(Irssi::settings_get_bool('mpd_show_mode')) {
435 my $mode = $MPD{'status'}->{'repeat'}?"r":"";
436 $mode .= $MPD{'status'}->{'random'}?"z":"";
437 $info.="[$mode]";
439 $info.= ")";
440 $info=~s/\(\)$//;
442 $item->default_handler($get_size_only, undef, $info, 1)
445 ############################################################################
446 # Refresh the statusbar
448 sub mpdbar_refresh {
449 my $status;
450 my $csong;
452 eval { $status = $mpd->status; };
453 if($@) {
454 $MPD{'state'}="Error: $@";
455 Irssi::statusbar_items_redraw('mpdbar');
456 return;
459 eval { $csong = $mpd->current; };
460 if($@) {
461 $MPD{'state'}="Error: $@";
462 Irssi::statusbar_items_redraw('mpdbar');
463 return;
466 $MPD{'status'} = $status;
467 $MPD{'current'} = $csong;
468 $MPD{'state'} = $STATE{$status->{'state'}} || "?";
470 Irssi::statusbar_items_redraw('mpdbar');
473 ############################################################################
474 # Print songtitle etc to active window.
475 sub show {
476 my @actions=("np: ");
477 my $t = $MPD{'current'}->{'title'};
478 my $a = $MPD{'current'}->{'artist'};
479 Irssi::active_win()->command("/me ".$actions[rand(@actions)]."$a - $t");
482 ############################################################################
483 # Irssi-stuff
485 Irssi::statusbar_item_register('mpdbar', '{sb $0 $1 $2-}', 'mpdbar_setup');
486 Irssi::statusbars_recreate_items();
487 Irssi::timeout_add(1000, 'mpdbar_refresh', undef);
489 Irssi::command_bind('mshow','show');
490 Irssi::command_bind('mstop','stop');
491 Irssi::command_bind('mrepeat','repeat');
492 Irssi::command_bind('mrandom','random');
493 Irssi::command_bind('mplay','play');
494 Irssi::command_bind('mload','load');
495 Irssi::command_bind('madd','add');
496 Irssi::command_bind('mseek','seek');
497 Irssi::command_bind('mnext','next');
498 Irssi::command_bind('mprev','prev');
499 Irssi::command_bind('mpause','pause');
500 Irssi::command_bind('mvolume','volume');
501 Irssi::command_bind('mclear','clear');
502 Irssi::command_bind('minfo','info');
503 Irssi::command_bind('mremove','remove');