Annotation of mp3/daemon/playmp3s.pl, Revision 1.9
1.1 andrew 1: #!/usr/bin/perl
1.9 ! andrew 2: # $AFresh1$
1.1 andrew 3: ########################################################################
4: # PlayMP3.pl *** play's MP3s off a playlist using mp3play
5: #
6: # 04-14-00
7: # Written by andrew fresh <andrew@mad-techies.org>
8: ########################################################################
9:
10: use strict;
11: use warnings;
12: use diagnostics;
13:
14: use vars qw/ %cfgs /;
15:
16: my $config_file = shift || "/etc/playmp3s.conf";
17:
1.3 andrew 18: my %cfgs = readconfig($config_file);
19:
1.1 andrew 20: my $err_log = $cfgs{errors} || "/var/log/playmp3s.log";
21:
1.6 andrew 22: my $Num_History = 0;
1.4 andrew 23:
1.1 andrew 24: Print_PlayLog("Beginning playtime\n\n");
25:
26: my %Full_Playlist;
27: $Full_Playlist{last_mod} = 0;
28: my $playlist_last_mod = 0;
29:
30: my @playlist;
31:
1.9 ! andrew 32: my $playing = '';
1.8 andrew 33: for ( ;; ) {
34:
35: # while(1) {
36: my $save_playlist;
37:
1.9 ! andrew 38: if ( $cfgs{pausedfile} && -e $cfgs{pausedfile} ) {
! 39: Print_PlayLog("Paused\n");
! 40: DisplayPlaying( $cfgs{currenthtml}, "Paused" )
! 41: unless $playing eq 'paused';
! 42: $playing = 'paused';
! 43: sleep 10;
! 44: next;
! 45: }
! 46:
1.8 andrew 47: my ($last_mod) = ( stat( $cfgs{list} ) )[9];
48: if ( $playlist_last_mod != $last_mod ) {
49: @playlist = ();
50: $playlist_last_mod = $last_mod;
51: }
52:
53: while ( !@playlist ) {
54: Print_PlayLog("Getting Playlist . . .\n");
55:
56: # bail("getting playlist");
57: @playlist = get_playlist( $cfgs{list} );
58: unless (@playlist) {
59:
60: # bail("getting full playlist");
61: @playlist = get_full_playlist( $cfgs{fulllist} );
62:
63: Print_PlayLog("Got full playlist\n");
64: $save_playlist = 0;
65: }
66: else {
67: Print_PlayLog("Got normal playlist\n");
68: $save_playlist = 1;
69: }
70: unless (@playlist) { sleep 10; }
71: }
72: Print_PlayLog("Got playlist\n");
73:
74: Print_PlayLog("getting song to play . . .\n");
75: my $song = int rand( scalar(@playlist) );
76: my $filename = splice( @playlist, $song, 1 );
77: Print_PlayLog("\tGot $song - filename is\n\t$filename\n");
78:
79: Print_PlayLog("displaying file that is playing . . . ");
80: DisplayPlaying( $cfgs{currenthtml}, $filename );
1.9 ! andrew 81: $playing = $filename;
1.8 andrew 82: Print_PlayLog("done\n");
83:
84: Print_PlayLog("Adding Last. . .");
85: AddLast(
86: $filename, $cfgs{playedlist}, $Num_History,
87: $cfgs{playedhtml}, $cfgs{addurl}
88: );
89: Print_PlayLog("done\n");
90:
91: if ($save_playlist) {
92: Print_PlayLog("Saving Playlist. . .");
93: save_playlist( $cfgs{list}, @playlist )
94: || bail("Unable to save playlist!: $!");
95: Print_PlayLog("done\n");
96: }
97:
98: Print_PlayLog("Playing: $filename . . .\n");
99:
100: my $player;
101: my $play = "$cfgs{basedir}$filename";
102: if ( defined $filename && $filename =~ /\.mp3$/i ) {
103: $player = $cfgs{mp3play};
104: }
105: elsif ( $filename =~ /\.ogg$/i ) {
106: $player = $cfgs{oggplay};
107:
108: #$play =~ s/(\(|\)|&|"|'| |-)/\\$1/g;
109: }
110:
111: if ( not $player =~ s/\{\}/"$play"/g ) {
112: $player .= ' "' . $play . '"';
113: }
114: Print_PlayLog("$player\n");
115: `$player`;
116:
117: # my $kid = 0;
118: # while ($kid ne -1 && ContinueRun()) {
119: # while ($kid ne -1) {
120: # print "waiting to end . . . ";
121: # my $kid = waitpid(-1,&WNOHANG);
122: # print "done.\n";
123: # }
124:
125: Print_PlayLog("Displaying Nothing . . .");
126: DisplayPlaying( $cfgs{currenthtml}, "Nothing" );
1.9 ! andrew 127: $playing = 'nothing';
1.8 andrew 128: Print_PlayLog("done\n");
129:
130: #@playlist = ();
131:
132: sleep 1;
1.1 andrew 133: }
134:
1.8 andrew 135: sub Install {
1.1 andrew 136:
137: # add your additional install messages or functions here
138: print "\nThank you for installing this file\n";
139: }
140:
141: sub Remove {
1.8 andrew 142:
1.1 andrew 143: # add your additional remove messages or functions here
144: print "\nSorry you had to leave\n";
145: }
146:
147: sub Help {
1.8 andrew 148:
1.1 andrew 149: # add your additional help messages or functions here
150: print "\nYou don't really need help do you??\n";
151: }
152:
153: #########################################################################
154: # GetTime
155: sub GetTime {
1.8 andrew 156: my $hours = shift || 0;
157: my ( $sec, $min, $hour, $mday, $mon, $year,,, )
158: = localtime( time - ( 3600 * $hours ) ); # 86400 seconds is one day
159:
160: if ( $min < 10 ) { $min = "0$min" }
161: if ( $sec < 10 ) { $sec = "0$sec" }
162: if ( $hour < 10 ) { $hour = "0$hour" }
163: if ( $mday < 10 ) { $mday = "0$mday" }
164: if ( $mon < 10 ) { $mon = "0$mon" }
165:
166: my $time
167: = ( $year + 1900 ) . '-'
168: . ++$mon . '-'
169: . $mday . ' '
170: . $hour . ':'
171: . $min . ':'
172: . $sec;
173: return $time;
1.1 andrew 174: }
175: #########################################################################
176:
177: #######################################################################
178: # read in the Playlist
179: sub get_full_playlist {
1.8 andrew 180: my $FILE = shift;
181: my ($last_mod) = ( stat($FILE) )[9];
1.1 andrew 182:
1.8 andrew 183: if ( $Full_Playlist{last_mod} != $last_mod ) {
184: my @list;
185: @list = get_playlist($FILE);
186:
187: @list = grep !m#$cfgs{skipregex}#io, @list;
188:
189: my @played_list = get_playlist( $cfgs{playedlist} );
190:
191: my %played;
192: @played{@played_list} = ();
193:
194: delete $Full_Playlist{list};
195:
196: my $list_size = 0;
197: foreach my $song (@list) {
198: $list_size++;
199: $Full_Playlist{list}{$song} = 1
200: unless ( exists $played{$song} );
201: }
202: my $history = int $list_size * 0.1;
203: if ($history) {
204: Print_PlayLog("New history is $history\n");
205: $Num_History = $history;
206: }
1.1 andrew 207:
1.8 andrew 208: $Full_Playlist{last_mod} = $last_mod;
209: }
1.1 andrew 210:
1.8 andrew 211: return keys %{ $Full_Playlist{list} };
1.1 andrew 212: }
213: #######################################################################
214:
215: #######################################################################
216: # read in the Playlist
217: sub get_playlist {
1.8 andrew 218: my $FILE = shift;
219: my @lines;
1.1 andrew 220:
1.8 andrew 221: # open PLAYlistLOG, ">c:/ps/playlistlog.txt";
1.1 andrew 222:
1.8 andrew 223: # print PLAYlistLOG "Getting Playlist from file: $FILE\n";
224: # close PLAYlistLOG;
225: if ( -e $FILE ) {
226: open( FILE, $FILE ) || bail("Couldn't open $FILE: $!");
227: chomp( @lines = <FILE> );
228: close(FILE) || bail("Couldn't close $FILE: $!");
229: }
230: else {
231: open( FILE, ">$FILE" ) || return @lines;
232: close(FILE) || bail("Couldn't close $FILE: $!");
233: return @lines;
234: }
235: return @lines;
236: }
1.1 andrew 237:
238: #######################################################################
239: # writes back the new playlist
240: sub save_playlist {
1.8 andrew 241: my $FILE = shift;
242: my @lines = @_;
243: open( FILE, ">$FILE" )
244: || bail("Couldn\'t open playlist to save $FILE: $!");
245: foreach (@lines) {
246: print FILE "$_\n";
247: }
248: close(FILE) || bail("Couldn't close $FILE: $!");
249: return 1;
1.1 andrew 250: }
251:
252: #######################################################################
253: # Prints a webpage with the currently playing song
254: sub DisplayPlaying {
1.8 andrew 255:
256: my $htmlfile = shift;
257: my $playing = shift;
258:
259: open BLANK, ">$htmlfile" or bail("Unable to open $htmlfile: $!");
260: print BLANK "<html>\n<head>\n\t<title>' . $playing . '</title>\n";
261: print BLANK "<meta HTTP-EQUIV=\"REFRESH\" CONTENT=\"5\">\n";
262: print BLANK "<meta HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">\n";
263: print BLANK "</head>\n";
264: print BLANK '<body leftmargin="0" topmargin="0" ',
265: 'marginwidth="0" marginheight="0">', "\n\n";
266: print BLANK
267: "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">\n";
268: print BLANK " <tr>\n";
269: print BLANK
270: " <td align=\"left\"><b><i>Currently playing:</i> $playing</b></td>\n";
271: print BLANK " <td align=\"right\">Started at: "
272: . GetTime()
273: . "</td>\n";
274: print BLANK " </tr>\n";
275: print BLANK "</table>\n";
1.1 andrew 276:
277: # print BLANK "<center><b>Currently playing: $playing</b><br>\nStarted at: " . GetTime() . "</center>";
278:
1.8 andrew 279: print BLANK "</body>\n</head>\n</html>\n";
280: close BLANK || bail("Unable to close BLANK: $!");
1.1 andrew 281: }
282:
283: #######################################################################
284: # Prints a webpage with the previously played song
1.6 andrew 285: # AddLast($filename, $cfgs{playedlist}, $Num_History, $cfgs{playedhtml}, $cfgs{addurl});
1.1 andrew 286: sub AddLast {
1.8 andrew 287: my $lastsong = shift;
288: my $lastlist = shift;
289: my $history = shift;
290: my $htmlfile = shift;
291: my $addurl = shift;
292:
293: my @LIST = get_playlist($lastlist);
294:
295: DisplayPrevious( $htmlfile, $addurl, @LIST ) if $htmlfile;
296:
297: unshift @LIST, $lastsong;
298: splice( @LIST, $history ) if $history;
299: save_playlist( $lastlist, @LIST );
1.7 andrew 300:
1.8 andrew 301: # Remove song from full list so we don't play it again.
302: delete $Full_Playlist{list}{$lastsong};
1.1 andrew 303: }
304:
305: #######################################################################
306: # Prints a webpage with the previously played song
307: sub DisplayPrevious {
308:
1.8 andrew 309: my $htmlfile = shift;
310: my $addurl = shift;
311: my $lastplay = shift;
312: my @played = @_;
313: open BLANK, ">$htmlfile" or bail("Unable to open $htmlfile: $!");
314: print BLANK "<html>\n<head>\n\t<title>' . $lastplay . '</title>\n";
315: print BLANK "<meta HTTP-EQUIV=\"REFRESH\" CONTENT=\"30\">\n";
316: print BLANK "<meta HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">\n";
317: print BLANK "<body>\n\n";
318:
319: print BLANK "<p>[ <a href=\"bin/ShowFiles.pl\">Beginning</a> | \n";
320: print BLANK "<a href=\"bin/ShowAll.pl\">All MP3's</a> |\n";
321: print BLANK "<a href=\"bin/ShowPlaylist.pl\">Playlist</a> |\n";
322: print BLANK "<a href=\"ShowPlaylist.pl?newlist.lst\">New Files</a> |\n";
323: print BLANK "<a href=\"played.htm\">Previously played</a> ]<p>\n";
324:
325: print BLANK "<center><b>Last played: <a href=\"$addurl\?"
326: . EncodeURL("$lastplay")
327: . "\" target=\"bottom\">$lastplay</a></b><br>\nStarted at: "
328: . GetTime()
329: . "</center><p>\n";
330:
331: print BLANK "before that:<br>\n";
332:
333: print BLANK "<UL>\n";
334:
335: foreach my $song (@played) {
336: print BLANK "\t<li>Song: <a href=\"$addurl\?"
337: . EncodeURL("$song")
338: . "\" target=\"bottom\">$song</a></li>\n";
339: }
1.1 andrew 340:
1.8 andrew 341: print BLANK "</UL>\n";
1.1 andrew 342:
1.8 andrew 343: print BLANK "</body>\n</head>\n</html>\n";
344: close BLANK || bail("Unable to close played.htm: $!");
1.1 andrew 345: }
346:
347: ########################################################################
348: # *** EncodeURL: %encodes the parameters of the URL
349: sub EncodeURL {
1.8 andrew 350: my $strURL = shift;
351: $strURL =~ s/(\W)/sprintf("%%%x", ord($1))/eg;
352: return $strURL;
1.1 andrew 353: }
354:
355: ########################################################################
356: # read in config file.
357: sub readconfig {
1.8 andrew 358: my $CONFIG = shift;
359: my $delimter = shift || '=';
360: my %configs;
361: if ( -e $CONFIG ) {
362: open( CONFIG, $CONFIG ) or bail("Couldn\'t open $CONFIG: $!");
363: while (<CONFIG>) {
364: chomp; # no newline
365: s/#.*//; # no comments
366: s/^\s+//; # no leading white space
367: s/\s+$//; # no trailing white space
368: next unless length; # anything left?
369: my ( $var, $value ) = split( /\s*$delimter\s*/, $_, 2 );
370:
371: # $var =~ tr/A-Za-z0-9_\.\,\/\\ / /cd; # delete all the non alphanumerics
372: # $value =~ tr/A-Za-z0-9_\/\.\,\\ / /cd; # delete all the non alphanumerics
373: $var =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
374: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
375: $configs{$var} = $value;
376: }
377: close CONFIG or bail("Couldn't close $CONFIG: $!");
378: }
379: else {
380: print '<!-- No config file: ' . $CONFIG;
381: print ' -->';
382: print "\n";
383: }
384: return %configs;
1.1 andrew 385: }
386: ########################################################################
387:
1.8 andrew 388: #sub ForkMP3Player { # This forks the MP3 player.
1.1 andrew 389: ## KillPlaying(0);
1.8 andrew 390: #
1.1 andrew 391: # my $player = shift;
392: # my $song = shift;
393: #
394: # $player =! s/%%f%%/\"$song\"/ig;
395: #
1.8 andrew 396: #
1.1 andrew 397: # FORK: {
398: # if ($Mp3Playerpid = fork) {
399: # # parent here
400: ## print "\nMp3Playerpid: ", $Mp3Playerpid;
401: # # child process pid is available in $pid
402: # print "Parent PID: $Mp3Playerpid\n";
403: # } elsif (defined $Mp3Playerpid) { # $pid is zero here if defined
404: # # child here
405: # print "\nPlaying $song\n";
406: ## exec("$configs{mp3play} -b 16384 --reopen --aggressive -m \"$song\"");
407: # print "\n";
408: ## exec("$player \"$song\"");
409: # exec("$player");
410: # exit(0);
411: # # parent process pid is available with getppid
1.8 andrew 412: # } elsif ($! =~ /No more process/) {
1.1 andrew 413: # # EAGAIN, supposedly recoverable fork error
414: # sleep 5;
415: # redo FORK;
416: # } else {
417: # # weird fork error
418: # bail("\nCan't fork: $!");
419: # }
420: # }
421: #}
422:
1.8 andrew 423: #######################################################################
424: # Bail: this subrouting dies and displays the error to the browser.
425: # gotten from the example in the O'Reilly
426: # _Learning_Perl_on_Win32_Systems_
427: sub bail {
428: open ERR, '>>$err_log';
429:
430: # open ERR, ">>c:/ps/error.txt";
1.1 andrew 431:
1.8 andrew 432: my $error = "@_";
433: print "Unexpected Error: $error\n";
434: print ERR "Unexpected Error: $error\n";
435: close ERR;
1.1 andrew 436:
1.8 andrew 437: # exit;
438: }
1.1 andrew 439:
1.8 andrew 440: sub Print_PlayLog {
441: open PLAYLOG, ">>/tmp/playlog" or bail("Unable to open PLAYLOG");
442: print GetTime(), "\t", @_;
443: print PLAYLOG GetTime(), "\t", @_;
444: close PLAYLOG;
1.1 andrew 445: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>