#!/usr/bin/perl use strict; use Getopt::Std; use List::Util qw(shuffle); use File::Find; # TODO: # - Read song list from file # - Go backwars in playlist # - Seek inside of a song # This is the mapping we use to play a file # regex => 'command' # for the most simple case # regex => subref # for anything more complex my $map = { qr/\.ogg$/i => 'ogg123', qr/\.mp3$/i => 'mpg123', }; my %opt; getopts('hvz',\%opt); my @songs = @ARGV; # Check for songs given on STDIN if(!@songs) { @songs = ; chomp @songs; } if(!@songs || $opt{h}) { print qq{ polly - call an appropriate player for the given audio media Usage: polly [-hzv] file1.mp3 file2.ogg *.mp3 ... -h: show this -v: be verbose -z: shuffle the file list Also note that ^C during playback goes to next song, and two quick ^C's kill. If no songs are given, I'll try looking for them on STDIN. }; exit; } # If any song is a directory we should recurse my @songs_copy = @songs; foreach my $song (@songs_copy) { if(-d $song) { print "Adding all files in $song\n" if $opt{v}; find(sub { push @songs, $File::Find::name unless -d $File::Find::name}, $song); } } if($opt{z}) { print "Shuffling list...\n" if $opt{v}; @songs = shuffle @songs; } else { @songs = sort @songs; } use Curses::UI; my $cui = new Curses::UI( -color_support => 1, -compat => 1); my $win = $cui->add('window_id', 'Window'); $cui->set_binding( sub { exit }, "\cQ"); my ($searchtext, $listbox); $listbox = $win->add( 'mylistbox', 'Listbox', -values => [@songs], -radio => 1, -y => 1, -onchange => sub { my ($self) = @_; my $regex_list = $searchtext->get(); my @regexes = split /\s+/, $regex_list; my @songlist = @songs; my @songlist = @songs; foreach my $regex (@regexes) { @songlist = grep { /$regex/i } @songlist; } my $cur_idx = $self->id(); my $song = $songlist[$cur_idx]; playsong($song); } ); $searchtext = $win->add( 'searchbox','TextEntry', -onchange => sub { my ($self) = @_; my $regex_list = $self->get(); my @regexes = split /\s+/, $regex_list; my @songlist = @songs; foreach my $regex (@regexes) { @songlist = grep { /$regex/i } @songlist; } @songlist = map { s/.*\///; $_ } @songlist; $listbox->values([@songlist]); $listbox->draw(); }, ); $searchtext->focus(); $cui->mainloop; sub playsong { my ($song) = @_; my ($type) = grep { $song =~ /$_/ } keys %$map; if($type) { my $cmd = $map->{$type}; #print "$song\n"; my $extra = ''; $extra = '2&> /dev/null' unless $opt{v}; eval { local $SIG{INT} = sub { die "INTERRUPT"; }; if(ref $cmd) { $cmd->($song); } else { `$cmd '$song' $extra`; } }; if($@ =~ 'INTERRUPT') { print "\nGoing to next song...\n"; sleep 1; # Give them a chance to interrupt again } elsif($@) { die "Error: $@\n"; } } else { print "Didn't find type for $song\n" if $opt{v}; } } foreach my $song (@songs) { playsong($song); }