1#/usr/bin/perl -w
2########################################################################
3#
4# iMPD - irssi MPD controller
5# Copyright (C) 2004 Shawn Fogle (starz@antisocial.com)
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20#
21########################################################################
22#
23# iMPD - irssi MPD
24#
25# Requirements: mpc, mpd (http://musicpd.org)
26#
27# Please report b00gs to http://www.musicpd.org/forum/viewtopic.php?t=19
28# Get the latest and greatest from pulling the module at musicpd's
29# SVN (module iMPD).
30#
31# OK, This is the a script for irssi/mpc/mpd for people who want to
32# control mpd from irssi. It's very bloated, and featureful, but this
33# is a good thing because it's just a perl script and you really don't
34# ever need to use anything that's in here that doesn't pertain to you.
35# If you need it (or want it) it's most likely in here.
36#
37# I am up for suggestions, alot of this may not work for you, and
38# I will not fix it unless you tell me about it.
39#
40# I do not believe in backwards compatibility if that means it gets in
41# the way of development, so this is probably needs the latest and
42# greatest due to changes in mpc/mpd.
43#
44########################################################################
45#                           Changes
46########################################################################
47#
48#  0.0.0m->0.0.0n
49#
50#  - Added Move / Crossfade
51#
52#  - Fixed problems with finding mpc if it's in your path.
53#
54#  - Began work on AddNext (Adding next in the queue, unless it's on
55#    random or shuffle, don't know if it will ever be added but this
56#    release needs to make it out soon to fix path b00g.
57#
58#  - Finally attached the GPL to make this fully GPLv2 compatible
59#
60########################################################################
61#           Buglist / Wishlist / Todo (In no particular order)
62########################################################################
63#
64# - Have to be able to tell if MPD goes down, so it can gracefully
65#   shutdown the statusbar, so it doesn't try and access mpc every
66#   5 seconds (gets even worse if mpdbar_refresh is faster than
67#   default). This will more than likely be fixed by the MPD module.
68#   Note to self: Script unloading self leads to _bad_problems ;p
69#
70# - Update issues will go away in 0.11.0 (see musicpd.org) due to
71#   update being non-blocking from there on out (hopefully ;p)
72#
73########################################################################
74# You don't need to edit below this unless you know what you're doing :)
75########################################################################
76
77use File::Basename;
78use Irssi;
79use Irssi::TextUI;
80use strict;
81use vars qw($VERSION %ENABLED %SAVE_VARS %IRSSI %COUNT %SET);
82
83$VERSION = '0.0.0n';
84%IRSSI = (
85	  authors     => 'Santabutthead',
86	  contact     => 'starz@antisocial.com',
87	  name        => 'iMPD',
88	  description => 'This controls Music Player Daemon from the familiar irssi interface',
89	  sbitems     => 'mpdbar',
90	  license     => 'GPL v2',
91	  url         => 'http://www.musicpd.org'
92	  );
93
94# Create $SET{'mpc_override'}="/outside/path" if mpc's not in your path
95
96### DO NOT EDIT THESE! Use /set mpd_host /set mpd_port ###
97
98$SET{'port'} = "2100";
99$SET{'host'} = "127.0.0.1";
100
101### Let's go ahead and set this up, so irssi doesn't have a tantrum ###
102
103Irssi::signal_add('setup changed' => \&read_settings);
104Irssi::settings_add_bool('misc', 'mpdbar_bottom', 0);
105Irssi::settings_add_bool('misc', 'mpdbar_top', 0);
106Irssi::settings_add_bool('misc', 'mpdbar_window', 0);
107Irssi::settings_add_bool('misc', 'current_window', '0');
108Irssi::settings_add_int('misc', 'output_window', '1');
109Irssi::settings_add_int('misc', 'mpd_port', '2100');
110Irssi::settings_add_str('misc', 'mpd_host', '127.0.0.1');
111Irssi::signal_add_first('command script unload', \&cleanup);
112Irssi::signal_add_first('command script load', \&cleanup);
113Irssi::signal_add('setup changed' => \&mpdbar_refresh);
114# Keep the $2- to treat spaces right
115Irssi::statusbar_item_register('mpdbar', '{sb $0 $1 $2-}', 'mpdbar_setup');
116Irssi::statusbars_recreate_items();
117
118#######################################################################
119
120print "For usage information on iMPD type /mhelp";
121
122sub add {
123    if ($_[0]) {
124	&read_settings;
125	my $j;
126	&current_window;
127	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
128	    my @i = split / /, $_[0];
129	    $j = $i[0];
130	    $_[0] =~ s/^(\w+)\s//;
131	} else {
132	    $j = "filename";
133	}
134	Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add" );
135	&set_active;
136    } else {
137	print "%W/madd (album|artist|filename|title) {search term} {search term}..%w";
138	print " - Search for {search term} and automagically add it to the end of the queue";
139	print " - This command does not support play number. (it doesn't make sense)";
140	print " - If not specified it will use filename by default";
141    }
142}
143
144sub addall {
145    &read_settings;
146    &current_window;
147    Irssi::command( "$SET{'intrairssi'} add \"\"" );
148    &set_active;
149}
150
151sub addallPlay {
152    &read_settings;
153    &current_window;
154    Irssi::command( "$SET{'intrairssi'} add \"\" && $SET{'intrashell'} play" );
155    &mpdbar_refresh; # Impatience
156    &set_active;
157}
158
159sub addallShufflePlay {
160    &read_settings;
161    &current_window;
162    Irssi::command( "$SET{'intrairssi'} add \"\" && $SET{'intrashell'} shuffle && $SET{'intrashell'} play" );
163    &mpdbar_refresh; # Impatience
164    &set_active;
165}
166
167sub addNext {  # This does not work yet, but doesn't hurt being here until it does :)
168    if ($_[0]) {
169	&read_settings;
170	my $j;
171	&current_window;
172	&song_count;
173	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
174	    my @i = split / /, $_[0];
175	    $j = $i[0];
176	    $_[0] =~ s/^(\w+)\s//;
177	} else {
178	    $j = "filename";
179	}
180	Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add" );
181	my $new_pos =~ $COUNT{'song'}++;
182	my $playcount =~ $COUNT{'playlist'}++;
183	Irssi::command( "$SET{'intrairssi'} mpc $playcount $new_pos");
184	#random detect stuff here;
185	&set_active;
186    } else {
187	print "%W/maddnext (album|artist|filename|title) {search term} {search term}..%w";
188	print " - Search for {search term} and automagically add it to the next position in";
189        print " - the queue. This command does not support play number. (it doesn't make sense)";
190	print " - If not specified it will use filename by default";
191    }
192}
193
194sub addPlay {
195    if ($_[0]) {
196	&read_settings;
197	my $j;
198	&current_window;
199	if ($_[0]=~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
200	    my @i = split / /, $_[0];
201	    $j = $i[0];
202	    $_[0] =~ s/^(\w+)\s//;
203	} else {
204	    $j = "filename";
205	}
206	Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} play" );
207	&mpdbar_refresh; # Impatience
208	&set_active;
209    } else {
210	print "%W/map (add play) (album|artist|filename|title) {search term} {search term}..%w";
211	print " - Search for {search term} and automagically add it to the end of the queue";
212	print " - This command does not support play number. (it doesn't make sense)";
213	print " - If not specified it will use filename by default";
214    }
215}
216
217sub addShuffle {
218    if ($_[0]) {
219	&read_settings;
220	my $j;
221	&current_window;
222	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
223	    my @i = split / /, $_[0];
224	    $j = $i[0];
225	    $_[0] =~ s/^(\w+)\s//;
226	} else {
227	    $j = "filename";
228	}
229	Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} shuffle" );
230	&set_active;
231    } else {
232	print "%W/mas (add shuffle) (album|artist|filename|title) {search term} {search term}..%w";
233	print " - Search for {search term} and automagically add it to the end of the queue";
234	print " - This command does not support play number. (it doesn't make sense)";
235	print " - If not specified it will use filename by default";
236    }
237}
238
239sub addShufflePlay {
240    if ($_[0]) {
241	&read_settings;
242	my $j;
243	&current_window;
244	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
245	    my @i = split / /, $_[0];
246	    $j = $i[0];
247	    $_[0] =~ s/^(\w+)\s//;
248	} else {
249	    $j = "filename";
250	}
251	Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} shuffle && $SET{'intrashell'} play" );
252	&mpdbar_refresh; # Impatience
253	&set_active;
254    } else {
255	print "%W/masp (add shuffle play) (album|artist|filename|title) {search term} {search term}..%w";
256	print " - Search for {search term} and automagically add it to the end of the queue";
257	print " - This command does not support play number. (it doesn't make sense)";
258	print " - If not specified it will use filename by default";
259    }
260}
261
262
263sub cleanup {
264    my ($file) = Irssi::get_irssi_dir."/iMPD.conf";
265
266    open CONF, ">", $file;
267    for my $net (sort keys %SAVE_VARS) {
268	print CONF "$net\t$SAVE_VARS{$net}\n";
269	close CONF;
270    }
271    Irssi::command( "statusbar mpdbar disable" );
272  }
273
274sub clear {
275    &read_settings;
276    &current_window;
277    Irssi::command( "$SET{'intrairssi'} clear" );
278    &mpdbar_refresh; # Impatience
279    &set_active;
280}
281
282sub clearAddAllPlay {
283    &read_settings;
284    &current_window;
285    Irssi::command( "$SET{'intrairssi'} clear && $SET{'intrashell'} add \"\" && $SET{'intrashell'} play" );
286    &mpdbar_refresh; # Impatience
287    &set_active;
288}
289
290sub clearAddAllShufflePlay {
291    &read_settings;
292    &current_window;
293    Irssi::command( "$SET{'intrairssi'} clear && $SET{'intrashell'} add \"\" && $SET{'intrashell'} shuffle && $SET{'intrashell'} play" );
294    &mpdbar_refresh; # Impatience
295    &set_active;
296}
297
298sub clearAddPlay {
299    if ($_[0]) {
300	&read_settings;
301	my $j;
302	&current_window;
303	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
304	    my @i = split / /, $_[0];
305	    $j = $i[0];
306	    $_[0] =~ s/^(\w+)\s//;
307	} else {
308	    $j = "filename";
309	}
310	Irssi::command( "$SET{'intrairssi'} clear && $SET{'intrashell'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} play" );
311	&mpdbar_refresh; # Impatience
312	&set_active;
313    } else {
314	print "%W/mcap (clear add play) (album|artist|filename|title) {search term} {search term}..%w";
315	print " - Search for {search term} and automagically add it to the end of the queue";
316	print " - This command does not support play number. (it doesn't make sense)";
317	print " - If not specified it will use filename by default";
318    }
319}
320
321sub clearAddShufflePlay {
322    if ($_[0]) {
323	&read_settings;
324	my $j;
325	&current_window;
326	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
327	    my @i = split / /, $_[0];
328	    $j = $i[0];
329	    $_[0] =~ s/^(\w+)\s//;
330	} else {
331	    $j = "filename";
332	}
333	Irssi::command( "$SET{'intrairssi'} clear && $SET{'intrashell'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} shuffle && $SET{'intrashell'} play" );
334	&mpdbar_refresh; # Impatience
335	&set_active;
336    } else {
337	print "%W/mcasp (clear add shuffle play) (album|artist|filename|title) {search term} {search term}..%w";
338	print " - Search for {search term} and automagically add it to the end of the queue";
339	print " - This command does not support play number. (it doesn't make sense)";
340	print " - If not specified it will use filename by default";
341    }
342}
343
344sub clearback {
345    &read_settings;
346    &song_count;
347    &current_window;
348    Irssi::command( "$SET{'intrairssi'} del $COUNT{'sr1'}" );
349    &set_active;
350}
351
352sub crossfade {
353    &read_settings;
354    if ($_[0] =~ m/\d{1-4}/) {
355	&current_window;
356	Irssi::command( "$SET{'intrairssi'} crossfade $_[0]" );
357	&mpdbar_refresh; # Impatience
358	&set_active;
359    } else {
360	print "%W/mcrossfade <num> %w- Number of seconds to crossfade between songs";
361    }
362}
363
364sub current_status{
365    &read_settings;
366    &current_window;
367    my $i = `$SET{'intrashell'}`;
368    chomp($i);
369    $SET{'active'}->print( $i );
370    &set_active;
371    return;
372}
373
374sub current_window {
375    $SET{'active'} = Irssi::active_win();
376    if (! $SET{'current'}) {
377	Irssi::window_find_refnum($SET{'output'})->set_active;
378      }
379}
380
381sub delete {
382    if($_[0]) {
383	my (@i,$j,$k);
384	@i = split / /, $_[0];
385	$j = shift(@i);
386
387	&read_settings;
388	&current_window;
389	# You may ask why? This is for the future when del (hopefully) has useful output
390	$k = "$SET{'intrairssi'} playlist | grep \"$j\" | $SET{'intrashell'} del";
391	$_[0] =~ s/^(\w+)\s//;
392	$k = "$k && $SET{'intrashell'} playlist | grep \"$_[0]\" | $SET{'intrashell'} del";
393	Irssi::command( "$k" );
394	&set_active;
395    } else {
396	print"%W/mdel {search term} {search term}..%w";
397        print" - Search for {search term} and automagically";
398	print" - delete it from the queue";
399    }
400}
401
402sub iMPD_help {
403my $mpd_help = <<MPD_HELP;
404    %r---=[ %WMusic Control Commands %r]=---%w
405    %W/mmute                      %w- Mutes/Unmutes the volume
406    %W/mnext                      %w- Starts playing next song on playlist
407    %W/mpause                     %w- Pauses playing
408    %W/mplay <number>             %w- Starts MPD (with optional number of song
409                                              to start on)
410    %W/mprev                      %w- Previous Song
411    %W/mstop <minutes> <m|h|d>    %w- Stops the current playlist,
412                                  options are minutes, hours and days, seconds
413                                  are the default
414    %W/mupdate                    %w- Update MPD Database
415    %W/mvolume <value> (0-100)    %w- Sets the volume on the OSS mixer
416                                  to <value> (0-100)
417
418    %r---=[ %WSearch Commands %r]=---%w
419    %W/madd (album|artist|filename|title) {search term} {search term} ..%w
420                                %w- Search for {search term} and automagically
421                                    add it to the end of the queue, upto 5 search terms
422                                - If not specified it will use filename by default
423    %W/mdel {search term} {search term} ..%w
424                                %w- Search for {search term} and automagically
425                                    delete it from the queue
426    %W/msearch (album|artist|filename|title) {search term} {search term}..%w
427                                %w- Search for {search term}
428                                - If not specified it will use filename by default
429
430    %r---=[ %WNavigation/Playlist Commands %r]=---%w
431    %W/maddall                    %w- Add all known music to the playlist
432    %W/mclear                     %w- Clear the current playlist
433    %W/mclearback                 %w- Clears all songs before the current playing song
434    %W/mcrossfade <num>           %w- Number of seconds to crossfade between songs
435    %W/mls [<directory>]          %w- Lists all files/folders in <directory>
436    %W/mmove <num> <num>          %w- Move song on playlist
437    %W/mplaylist <range>          %w- Print entire playlist if there's no range
438                                - Otherwise will print the range (i.e. 1-10)
439    %W/mplaylistls                %w- List available playlists
440    %W/mplaylistload <file>       %w- Load playlist <file>
441    %W/mplaylistrm <file>         %w- Remove (delete) playlist <file>
442    %W/mplaylistsave <file>       %w- Save playlist <file>
443    %W/mpls {search term} {search term}...%w
444                                %w- Playlist search {search term}
445    %W/mseek <num>                %w- Seeks to the spot specified for the current file, in terms of percent time (0-100)
446    %W/mshuffle                   %w- Shuffle the MPD playlist
447    %W/mrandom                    %w- Play the playlist randomly
448    %W/mwipe                      %w- Remove all songs but the one currently playing
449
450    %r---=[ %WMiscellaneous Commands %r]=---%w
451    %W/mhelp                      %w- This screen
452    %W/mloud                      %w- Show everyone in the current window the MPD stats
453    %W/mlouder                    %w- Show everyone in the current window the MPD stats
454                                      *use with caution*
455    %W/minfo                      %w- Show MPD Status in the status window
456    %W/mrm <num> <num>..          %w- Remove song from the current playlist (by number
457                                %w- or number range)
458 See Also: /mhelpadv
459           /mhelpmpdbar
460           /set mpd_host mpd_port
461           /set mpd_current_window mpd_output_window (EXPERIMENTAL)
462MPD_HELP
463print $mpd_help;
464}
465
466sub iMPD_helpAdv{
467my $mpd_help_advanced = <<MPD_HELP_ADVANCED;
468    %r---=[ %WCombination Commands %r]=---%w
469    These do not take play arguments.
470    %W/map {search term} {search term} ..     %w- Add, Play
471    %W/maap                                   %w- Addall, Play
472    %W/maasp                                  %w- Addall, Shuffle, Play
473    %W/mas {search term} {search term} ..     %w- Add, Shuffle
474    %W/masp {search term} {search term} ..    %w- Add, Shuffle, Play
475    %W/mcap {search term} {search term} ..    %w- Clear, Add, Play
476    %W/mcaap                                  %w- Clear, Addall, Play
477    %W/mcaasp                                 %w- Clear, Addall, Shuffle, Play
478    %W/mcasp {search term} {search term} ..   %w- Clear, Add, Shuffle, Play
479    %W/mwa {search term} {search term} ..     %w- Wipe, Add,
480    %W/mwaa                                   %w- Wipe, Addall
481    %W/mwaas                                  %w- Wipe, Addall, Shuffle
482    %W/mwas {search term} {search term} ..    %w- Wipe, Add, Shuffle
483
484 See Also: /set mpd_port mpd_host
485           /set mpd_current_window mpd_output_window (EXPERIMENTAL)
486MPD_HELP_ADVANCED
487print $mpd_help_advanced;
488}
489
490sub load_settings {
491    my ($file) = Irssi::get_irssi_dir."/iMPD.conf";
492
493    open CONF, "<", $file;
494    while (<CONF>) {
495	my($net,$val) = split;
496	if ($net && $val) {
497	    $SAVE_VARS{$net} = $val;
498	}
499	close CONF;
500    }
501}
502
503# For those who want to be loud/annoying :)
504sub loud {
505    &read_settings;
506    my ($i,$j);
507    my @split = `$SET{'intrashell'}`;
508
509    if (! $split[1]) {
510	Irssi::print( "iMPD is not currently playing" );
511	  return;
512      }
513
514    $i = basename $split[0];
515    $i =~ s/[_]/ /g;
516# Feel free to put your personal PERL regexps here ;p
517# Experiment with these to do some wicked stuff to your loud output.
518#    $i =~ s/.mp3//ig;
519#    $i =~ s/.flac//ig;
520#    $i =~ s/.flc//ig;
521#    $i =~ s/.ogg//ig;
522#    $i =~ s/^\p{0,2}//;
523#    $i =~ s/[.]//g;
524    $i = substr($i,0,-1);
525
526    Irssi::active_win->command( "/me is listening to $i" );
527    close Reader;
528}
529
530sub louder {
531    &read_settings;
532    my @split=`$SET{'intrashell'}`;
533    chomp(@split);
534    Irssi::active_win->command( "/say $split[0]" );
535    Irssi::active_win->command( "/say $split[1]" );
536    Irssi::active_win->command( "/say $split[2]" );
537    close Reader;
538}
539
540sub ls {
541    if ($_[0]) {
542	&read_settings;
543	&current_window;
544	$_[0] =~ "\Q$_[0]\E";
545	$_[0] =~ s/^\\//; # Rid of beginning / it doesn't delimit correctly.
546	$_[0] =~ s/\///; # Help out the degenerates.
547	Irssi::command( "$SET{'intrairssi'} ls " . "\Q$_[0]\E" );
548	&set_active;
549    } else {
550	print "%W/mls [<directory>] %w- Lists all files/folders in <directory>.";
551    }
552}
553
554sub lsplaylists {
555    &read_settings;
556    &current_window;
557    Irssi::command( "$SET{'intrairssi'} lsplaylists" );
558    &set_active;
559}
560
561sub move {
562    &read_settings;
563    if ($_[0] =~ m/\d{1,2}\s{1,2}/) {
564	&current_window;
565	Irssi::command( "$SET{'intrairssi'} move $_[0]" );
566	&mpdbar_refresh; # Impatience
567	&set_active;
568    } else {
569	print "%W/mmove <num> <num>          %w- Move song on playlist";
570    }
571}
572
573sub mpdbar_help {
574my $mpdbarhelp = <<MPDBAR_HELP;
575 mpdbar was made to be a simple way to get your statusbar up and
576 to hide it when it's not playing. If you feel that I'm not being
577 flexable enough in my choices you're free to setup a statusbar
578 without these commands or present me with an idea for a new
579 mpdbar command. But the current ones are:
580
581 /set mpdbar_bottom on -
582     This command will (obviously) display a mpdbar on the bottom.
583
584 /set mpdbar_refresh <num> -
585     This command will set the refresh in seconds, it defaults to
586     5 seconds, you might be able to set it higher although I don't
587     recommend setting it higher if your mpd server is across a
588     network (of any kind ;p).
589
590 /set mpdbar_top on
591     This command will (obviously) display a mpdbar on the top.
592
593 /set mpdbar_window on
594     This command will (not-so-obviously) display a mpdbar next to your
595     current window statusbar.
596MPDBAR_HELP
597print $mpdbarhelp;
598}
599
600sub mpdbar_get_stats {
601### Variable map  ###
602# $SET{'stat_time'}-Time/Percent(change)
603# $SET{'stat_current'}-Status(change)
604# $SET{'songbase'}-basename filename
605    if(Irssi::settings_get_bool('mpdbar_bottom') or
606       Irssi::settings_get_bool('mpdbar_top') or
607       Irssi::settings_get_bool('mpdbar_window')) {
608	&read_settings;
609
610	($SET{'stat1'},$SET{'stat2'},$SET{'stat3'}) = undef;
611	($SET{'stat1'},$SET{'stat2'},$SET{'stat3'}) = `$SET{'intrashell'}`;
612	chomp($SET{'stat1'},$SET{'stat2'},$SET{'stat3'});
613
614	if ($SET{'stat2'} =~ m/(\d{1,5}\:\d{1,2}\s\(\d{1,3}\%\))/) {
615	    $SET{'stat_time'} = $1;
616	}
617	if ($SET{'stat2'} =~ m/\[(\w+)\]/) {
618	    $SET{'stat_current'} = $1;
619	}
620	if($SET{'stat2'} and $SET{'stat1'} =~ m/\//g) { # Not sure if this will have an effect :/
621	    $SET{'songbase'} = basename $SET{'stat1'};
622	} else {
623	    $SET{'songbase'} = $SET{'stat1'};
624	}
625    }
626}
627
628sub mpdbar_refresh {
629    if(Irssi::settings_get_bool('mpdbar_bottom') or
630       Irssi::settings_get_bool('mpdbar_top') or
631       Irssi::settings_get_bool('mpdbar_window')) {
632	&mpdbar_get_stats;
633	if (Irssi::settings_get_bool('mpdbar_bottom') and Irssi::settings_get_bool('mpdbar_top')) {
634	    Irssi::print( "Have not implemented ability to mpdbar top and bottom at the same time" );
635	      Irssi::print( "That's fine though, I'll just set it to the bottom for you for now" );
636	      Irssi::settings_set_bool('mpdbar_bottom',1);
637	      Irssi::settings_set_bool('mpdbar_top',0);
638	  }
639	if (Irssi::settings_get_bool('mpdbar_window') and $SET{'stat2'}) {
640	    $ENABLED{'window'} = "1";
641	    Irssi::command( "statusbar window add mpdbar" );
642	    Irssi::command( "statusbar window enable mpdbar" );
643	} else {
644	    if($ENABLED{'window'} == 1) {
645		Irssi::command( "statusbar window remove mpdbar" );
646		  $ENABLED{'window'} = 0;
647	      }
648	}
649	if (Irssi::settings_get_bool('mpdbar_bottom') and $SET{'stat2'} and ! $ENABLED{'top'}) {
650	    $ENABLED{'bottom'} = "1";
651	    Irssi::command( "statusbar mpdbar placement bottom" );
652	    Irssi::command( "statusbar mpdbar position 2" );
653	    Irssi::command( "statusbar mpdbar enable" );
654	    Irssi::command( "statusbar mpdbar add mpdbar" );
655	    Irssi::command( "statusbar mpdbar visible active" );
656	} else {
657	    if($ENABLED{'bottom'} == 1){
658		Irssi::command( "statusbar mpdbar remove mpdbar" );
659		  Irssi::command( "statusbar mpdbar disable" );
660		  $ENABLED{'bottom'} = 0;
661	      }
662	}
663	if (Irssi::settings_get_bool('mpdbar_top') and $SET{'stat2'} and ! $ENABLED{'bottom'}) {
664	    $ENABLED{'top'} = "1";
665	    Irssi::command( "statusbar mpdbar placement top" );
666	    Irssi::command( "statusbar mpdbar position 2" );
667	    Irssi::command( "statusbar mpdbar enable" );
668	    Irssi::command( "statusbar mpdbar add mpdbar" );
669	    Irssi::command( "statusbar mpdbar visible active" );
670	} else {
671	    if($ENABLED{'top'} == 1){
672		Irssi::command( "statusbar mpdbar remove mpdbar" );
673		  Irssi::command( "statusbar mpdbar disable" );
674		  $ENABLED{'top'} = 0;
675	      }
676	}
677    }
678}
679
680sub mpdbar_setup {
681    my ($item, $get_size_only) = @_;
682    if (! $SET{'stat2'}) { # If it's not on
683	$item->default_handler($get_size_only, undef, "$SET{'stat2'}", 1);
684    } else {
685	$SET{'stat_current'} =~ s/$SET{'stat_current'}/\u\L$SET{'stat_current'}/;
686	$item->default_handler($get_size_only, undef, "$SET{'stat_current'} $SET{'songbase'} $SET{'stat_time'}", 1);
687    }
688}
689
690sub mute {
691    &read_settings;
692    &current_window;
693
694    my @i = `$SET{'intrashell'}`;
695    my $j;
696    # This next conditional is for when the music is not playing
697    if (exists $i[2]) {
698	$j = $i[2];
699    } else {
700	$j = $i[0];
701    }
702    if ($j =~ m/volume\:\s{0,2}(\d{1,3})\%/) {
703	$j = $1;
704    }
705
706    if ($j != 0 and ! $SAVE_VARS{'muted'} == 0) {
707	print "Warning: Not currently muted, although it said it was";
708	delete $SAVE_VARS{'muted'}
709    }
710    if ($j == 0 and ! $SAVE_VARS{'muted'}) {
711	print "Error: Volume is currently muted, but I don't know how it got there. Manually set the volume please.";
712	delete $SAVE_VARS{'muted'};
713    }
714    if (!$SAVE_VARS{'muted'}) {
715	$SAVE_VARS{'muted'} = $j;
716	`$SET{'intrashell'} volume 0`;
717	print "Sound is muted, to unmute just hit /mmute again";
718    } else {
719	`$SET{'intrashell'} volume $SAVE_VARS{'muted'}`;
720	print "Reset the volume back to it's originial position ($SAVE_VARS{'muted'}%)";
721	delete $SAVE_VARS{'muted'};
722    }
723}
724
725sub next {
726    &read_settings;
727    &current_window;
728    Irssi::command( "$SET{'intrairssi'} next" );
729    &set_active;
730    &mpdbar_refresh; # Impatience
731}
732
733sub pause {
734    &read_settings;
735    &current_window;
736    Irssi::command( "$SET{'intrairssi'} pause" );
737    &mpdbar_refresh; # Impatience
738    &set_active;
739}
740
741sub play {
742    &read_settings;
743    my $i;
744    &current_window;
745    if ($_[0] =~ m/\d{1,6}/) {
746	$i = $_[0];
747    }
748    Irssi::command( "$SET{'intrairssi'} play $i" );
749    &mpdbar_refresh; # Impatience
750    &set_active;
751}
752
753sub playlist {
754    &read_settings;
755    my @playlist;
756    if ($_[0] =~ m/\d{1,6}\-\d{1,6}/) {
757	my ($head,$tail);
758	my @playlist = `$SET{'intrashell'} playlist`;
759	($head, $tail) = split /-/, $_[0];
760
761	# OK, just understand I'm here for you if you're
762	# tired enough to let this happen to you.
763	if($head > $tail) {
764	    my $i;
765	    $i = $head;
766	    $head = $tail;
767	    $tail = $i;
768	}
769
770	$head =~ $head--;
771	$tail = $tail - $head;
772	chomp $head;
773	chomp $tail;
774
775	@playlist = splice(@playlist,$head,$tail);
776	my $i = pop(@playlist);
777	chomp $i;
778	push (@playlist,$i);
779	print @playlist;
780    } else {
781	&current_window;
782	Irssi::command( "$SET{'intrairssi'} playlist" );
783	&set_active;
784    }
785}
786
787sub playlist_load {
788    if ($_[0]) {
789	&read_settings;
790	&current_window;
791	Irssi::command( "$SET{'intrairssi'} load \Q$_[0]\E" );
792	&set_active;
793    } else {
794	print "%W/mplaylistload <file> %w- Load playlist <file>";
795    }
796}
797
798sub playlist_remove {
799    if ($_[0]) {
800	&read_settings;
801	&current_window;
802	Irssi::command( "$SET{'intrairssi'} rm \Q$_[0]\E" );
803	&set_active;
804    }
805}
806
807sub playlist_save {
808    if ($_[0]) {
809	&read_settings;
810	&current_window;
811	Irssi::command( "$SET{'intrairssi'} save \Q$_[0]\E" );
812	&set_active;
813    } else {
814	print "%W/mplaylistsave <file> %w- Save playlist <file>";
815    }
816}
817
818sub playlistsearch {
819    if ($_[0]) {
820	&read_settings;
821	my @i = split / /, $_[0];
822	&current_window;
823	foreach(@i) {
824	    Irssi::command( "$SET{'intrairssi'} playlist | grep $_" );
825	  }
826	&set_active;
827    } else {
828	print "%W/pls {search term} {search term}..%w";
829	print " - Search for {search term} and automagically and show the playlist entry";
830    }
831}
832
833sub previous {
834    &read_settings;
835    &current_window;
836    Irssi::command( "$SET{'intrairssi'} prev" );
837    &mpdbar_refresh; # Impatience
838    &set_active;
839}
840
841sub random{
842    &read_settings;
843    &current_window;
844    Irssi::command( "$SET{'intrairssi'} random" );
845    &set_active;
846}
847
848sub read_settings {
849    ($SET{'mbar_time'}) && Irssi::timeout_remove($SET{'mbar_time'});
850    $SET{'mbar_time'}=Irssi::timeout_add(Irssi::settings_get_int('mpdbar_refresh') * 1000, 'mpdbar_refresh', undef);
851
852    $SET{'current'} = Irssi::settings_get_bool('current_window');
853    $SET{'output'} = Irssi::settings_get_int('output_window');
854
855    if (Irssi::settings_get_int( "mpd_port" )) {
856	$SET{'port'} = Irssi::settings_get_int( "mpd_port" );
857	$SET{'port'} = "MPD_PORT=$SET{'port'}"
858	}
859    if (Irssi::settings_get_str( "mpd_host" )) {
860	$SET{'host'} = Irssi::settings_get_str( "mpd_host" );
861	$SET{'host'} = "MPD_HOST=$SET{'host'}"
862    }
863    my $MPC_BIN;
864    if ( ! -x $SET{'mpc_override'} ) {
865	my @paths = split/:/,$ENV{'PATH'};
866
867	foreach(@paths) {
868	    my $path = $_;
869	    if( -x "$path" . "/" . "mpc" ) {
870		$MPC_BIN = "$path/mpc";
871	    }
872	}
873    } else {
874	$MPC_BIN = $SET{'mpc_override'};
875    }
876
877    if (! $MPC_BIN) {
878	print "mpc was not found in any of the known paths";
879	print "mpc is required to use this script, please download it from http://musicpd.org/files.php";
880    }
881
882    $SET{'intrashell'} = "$SET{'port'} $SET{'host'} $MPC_BIN";
883    $SET{'intrairssi'} = "exec - $SET{'intrashell'}";
884}
885
886sub repeat {
887    &read_settings;
888    &current_window;
889    Irssi::command( "$SET{'intrairssi'} repeat" );
890    &set_active;
891}
892
893sub remove_song {
894    &read_settings;
895    if ($_[0] =~ m/\d{1,6}/ or $_[0] =~ m/\d{1,6}\-\d{1,6}/) {
896	&current_window;
897	Irssi::command( "$SET{'intrairssi'} del $_[0]" );
898	&mpdbar_refresh; # Impatience
899	&set_active;
900    } else {
901	print "%W/mrm <num> <num>.. %w- Remove song from the current playlist (by number)";
902	print "%w                   - Note that <num> can be a range also";
903    }
904}
905
906sub search {
907    if ($_[0]) {
908	&read_settings;
909	my $j;
910	&current_window;
911	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
912	    my @i = split / /, $_[0];
913	    $j = $i[0];
914	    $_[0] =~ s/^(\w+)\s//;
915	} else {
916	    $j = "filename";
917	}
918	Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E" );
919	&set_active;
920    } else {
921	print "%W/search (album|artist|filename|title) {search term} {search term}..%w";
922	print " - Search for {search term} and automagically add it to the end of the queue";
923        print " - If not specified it will use filename by default";
924    }
925}
926
927sub seek {
928    &read_settings;
929    if ($_[0] =~ m/\d{1-3}/) {
930	&current_window;
931	Irssi::command( "$SET{'intrairssi'} seek $_[0]" );
932	&mpdbar_refresh; # Impatience
933	&set_active;
934    } else {
935	print "%W/mseek <num> %w- Seeks to the spot specified for the current file, in terms of percent time (0-100)";
936    }
937}
938
939sub set_active {
940    if (! $SET{'current'}) {
941	$SET{'active'}->set_active;
942    }
943}
944
945sub shuffle{
946    &read_settings;
947    &current_window;
948    Irssi::command( "$SET{'intrairssi'} shuffle" );
949    &set_active;
950}
951
952sub song_count {
953    %COUNT = undef;
954
955    my @counts = `$SET{'intrashell'}`;
956    chomp(@counts);
957
958    if ($counts[1] =~ m/\#(\d{1,6})\//) {
959	$COUNT{'song'} = $1;
960    }
961    if ($counts[1] =~ m/\/(\d{1,6})\s/) {
962	$COUNT{'playlist'} = $1;
963    }
964    if ($COUNT{'song'} > 1) {
965	my $i = $COUNT{'song'} - 1;
966	$COUNT{'sr1'} = "1-$i";
967    }
968    if ($COUNT{'song'} < $COUNT{'playlist'}){# and $COUNT{'song'} != $COUNT{'playlist'}) {
969	my $i = $COUNT{'song'} + 1;
970	$COUNT{'sr2'} = "$i-$COUNT{'playlist'}";
971    }
972}
973
974sub stop {
975    &read_settings;
976    my ($i,$time);
977    if ($_[0]) {
978	my $unit;
979	($time, $unit) = split / /, $_[0];
980	if ($unit =~ /minute/i or $unit =~ /minutes/i) {
981	    $time = ($time * 60);
982	}
983	if ($unit =~ /hour/i or $unit =~ /hours/i) {
984	    $time = ($time * 86400);
985	}
986	#ok. it's ridiculous to use this script for days, but in any case here ya go.
987	if ($unit =~ /day/i or $unit =~ /days/i) {
988	    $time = ($time * 2073600);
989	}
990	$time = $time . "s";
991	$i = "exec - /bin/sleep $time && $SET{'intrashell'} stop";
992    } else {
993	$i = "$SET{'intrairssi'} stop";
994    }
995    &current_window;
996    Irssi::command( "$i" );
997    &mpdbar_refresh; # Impatience
998    &set_active;
999}
1000
1001sub update {
1002    &read_settings;
1003    &current_window;
1004    Irssi::command( "$SET{'intrairssi'} update" );
1005    Irssi::print( "Irssi will not be accepting commands while updating" );
1006    &set_active;
1007}
1008
1009sub volume {
1010    &read_settings;
1011    &current_window;
1012    my (@i,$j);
1013    if ($_[0] =~ m/\d{1,3}/) {
1014	@i = `$SET{'intrashell'} volume $_[0]`;
1015    } else {
1016	@i = `$SET{'intrashell'}`;
1017    }
1018    # This next conditional is for when the music is not playing
1019    if (exists $i[2]) {
1020	$j = $i[2];
1021    } else {
1022	$j = $i[0];
1023    }
1024    if ($j =~ m/volume\:\s{0,2}(\d{1,3})\%/) {
1025	$j = $1;
1026    }
1027    # OK, if anyone wants to tell me _why_ this seems to be the only way
1028    # to get a "%" on the end please feel free (suspected to be due to
1029    # color codes
1030    if ($_[0]) {
1031	Irssi::print( "The volume is at $j%" . "%" );
1032    } else {
1033	$SET{'active'}->print( "The volume is at $j%" . "%" );
1034      }
1035    &set_active;
1036}
1037
1038sub wipe {
1039    &read_settings;
1040    &current_window;
1041    &song_count;
1042    if($COUNT{'sr1'} or $COUNT{'sr2'}) {
1043	Irssi::command( "$SET{'intrairssi'} del $COUNT{'sr1'} $COUNT{'sr2'}" );
1044      } else {
1045	  Irssi::print( "Can't wipe when there's only one song in the playlist" );
1046	}
1047    &set_active;
1048}
1049
1050sub wipeAdd{
1051    if ($_[0]) {
1052	&read_settings;
1053	&song_count;
1054	my $j;
1055	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
1056	    my @i = split / /, $_[0];
1057	    $j = $i[0];
1058	    $_[0] =~ s/^(\w+)\s//;
1059	} else {
1060	    $j = "filename";
1061	}
1062	&current_window;
1063	if($COUNT{'sr1'} or $COUNT{'sr2'}) {
1064	    Irssi::command( "$SET{'intrairssi'} del $COUNT{'sr1'} $COUNT{'sr2'} && $SET{'intrashell'} search $j \Q$_[0]\E | $SET{'intrashell'} add" );
1065	  } else { # Do the thinking for the person
1066	      Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add" );
1067	    }
1068	&set_active;
1069    } else {
1070	print "%W/mwa (wipe add) (album|artist|filename|title) {search term} {search term}..%w";
1071	print " - Search for {search term} and automagically add it to the end of the queue";
1072	print " - This command does not support play number. (it doesn't make sense)";
1073	print " - If not specified it will use filename by default"
1074	}
1075}
1076
1077sub wipeAddall{
1078    &read_settings;
1079    &song_count;
1080    &current_window;
1081    if($COUNT{'sr1'} or $COUNT{'sr2'}) {
1082	Irssi::command( "$SET{'intrairssi'} del $COUNT{'sr1'} $COUNT{'sr2'} && $SET{'intrashell'} add \"\"" );
1083      } else {
1084	  Irssi::command( "$SET{'intrairssi'} add \"\"" );
1085	}
1086    &set_active;
1087}
1088
1089sub wipeAddallShuffle{
1090    &read_settings;
1091    &song_count;
1092    &current_window;
1093    if($COUNT{'sr1'} or $COUNT{'sr2'}) {
1094	Irssi::command( "$SET{'intrairssi'} del $COUNT{'sr1'} $COUNT{'sr2'} && $SET{'intrashell'} add \"\" && $SET{'intrashell'} shuffle" );
1095      } else {
1096	Irssi::command( "$SET{'intrairssi'} add \"\" && $SET{'intrashell'} shuffle" );
1097      }
1098    &set_active;
1099}
1100
1101sub wipeAddShuffle{
1102    if ($_[0]) {
1103	&read_settings;
1104	my $j;
1105	if ($_[0] =~ /^album\s/ or $_[0]=~ /^filename\s/ or $_[0]=~ /^title\s/ or $_[0]=~ /^artist\s/ ) {
1106	    my @i = split / /, $_[0];
1107	    $j = $i[0];
1108	    $_[0] =~ s/^(\w+)\s//;
1109	} else {
1110	    $j = "filename";
1111	}
1112	&song_count;
1113	&current_window;
1114	if($COUNT{'sr1'} or $COUNT{'sr2'}) {
1115	    Irssi::command( "$SET{'intrairssi'} del $COUNT{'sr1'} $COUNT{'sr2'} && $SET{'intrashell'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} shuffle" );
1116	  } else {
1117	      Irssi::command( "$SET{'intrairssi'} search $j \Q$_[0]\E | $SET{'intrashell'} add && $SET{'intrashell'} shuffle" );
1118	    }
1119	&set_active;
1120    } else {
1121	print "%W/mwas (wipe add shuffle) (album|artist|filename|title) {search term} {search term}..%w";
1122	print " - Search for {search term} and automagically add it to the end of the queue";
1123	print " - This command does not support play number. (it doesn't make sense)";
1124	print " - If not specified it will use filename by default";
1125	}
1126}
1127Irssi::settings_add_int('misc', 'mpdbar_refresh', '5');
1128
1129&load_settings;
1130&mpdbar_refresh;
1131
1132Irssi::command_bind madd => \&add;
1133Irssi::command_bind maddall => \&addall;
1134# Irssi::command_bind maddnext => \&addNext;
1135Irssi::command_bind maap => \&addallPlay;
1136Irssi::command_bind maasp => \&addallShufflePlay;
1137Irssi::command_bind mas => \&addShuffle;
1138Irssi::command_bind masp => \&addShufflePlay;
1139Irssi::command_bind map => \&addPlay;
1140Irssi::command_bind mclear => \&clear;
1141Irssi::command_bind mclearback => \&clearback;
1142Irssi::command_bind mcaap => \&clearAddAllPlay;
1143Irssi::command_bind mcaasp => \&clearAddAllShufflePlay;
1144Irssi::command_bind mcap => \&clearAddPlay;
1145Irssi::command_bind mcasp => \&clearAddShufflePlay;
1146Irssi::command_bind mdel => \&delete;
1147Irssi::command_bind mls => \&ls;
1148Irssi::command_bind mhelp => \&iMPD_help;
1149Irssi::command_bind mhelpadv => \&iMPD_helpAdv;
1150Irssi::command_bind minfo => \&current_status;
1151Irssi::command_bind mloud => \&loud;
1152Irssi::command_bind mlouder => \&louder;
1153Irssi::command_bind mmute => \&mute;
1154Irssi::command_bind mnext => \&next;
1155Irssi::command_bind mpause => \&pause;
1156Irssi::command_bind mhelpmpdbar => \&mpdbar_help;
1157Irssi::command_bind mmove => \&move;
1158Irssi::command_bind mplay => \&play;
1159Irssi::command_bind mplaylist => \&playlist;
1160Irssi::command_bind mpls => \&playlistsearch;
1161Irssi::command_bind mplaylistls => \&lsplaylists;
1162Irssi::command_bind mplaylistload => \&playlist_load;
1163Irssi::command_bind mplaylistrm => \&playlist_remove;
1164Irssi::command_bind mplaylistsave => \&playlist_save;
1165Irssi::command_bind mprev => \&previous;
1166Irssi::command_bind mrandom => \&random;
1167Irssi::command_bind mrepeat => \&repeat;
1168Irssi::command_bind mrm => \&remove_song;
1169Irssi::command_bind mseek => \&seek;
1170Irssi::command_bind msearch => \&search;
1171Irssi::command_bind mshuffle => \&shuffle;
1172Irssi::command_bind mstop => \&stop;
1173Irssi::command_bind mupdate => \&update;
1174Irssi::command_bind mvolume => \&volume;
1175Irssi::command_bind mwa => \&wipeAdd;
1176Irssi::command_bind mwaa => \&wipeAddall;
1177Irssi::command_bind mwaas => \&wipeAddallShuffle;
1178Irssi::command_bind mwas => \&wipeAddShuffle;
1179Irssi::command_bind mwipe => \&wipe;
1180