#!/usr/bin/perl my $debug = 0; # Set to 1 to put the script in debug mode use POSIX; use DBI; use DBD::mysql; use Config::INI::Reader; my $confcontents = Config::INI::Reader->read_file('/etc/homeaudio.ini'); my $Config = $confcontents->{_}; $dsn = "DBI:mysql:" . $Config->{DBNAME} . ":" . $Config->{DBHOST}; $dbh = DBI->connect($dsn, $Config->{DBUSER}, $Config->{DBPASS}, {RaiseError=>1}); sub getNextSong() { # Set up our variables my $songid = 0; my $song = ""; my $qid = 0; # If Christmas is active we should always make sure that a # Christmas song has played within the last frequency interval. $sth = $dbh->prepare("SELECT value FROM settings WHERE parameter='CHRISTMAS'"); $sth->execute(); @row = $sth->fetchrow_array(); $sth->finish(); $christmasactive = $row[0] eq "true" ? 1 : 0; $forcechristmas = 0; if ( $christmasactive ) { if ( $debug ) { print "Christmas is active.\n"; } $sth = $dbh->prepare("SELECT value FROM settings WHERE parameter='CHRISTMASFREQ'"); $sth->execute(); @row = $sth->fetchrow_array(); my $christmasfreq = $row[0]; $sth->finish(); if ( $debug ) { print "Christmas frequency is (${christmasfreq}). Checking if Christmas song was played recently.\n"; } $sth = $dbh->prepare("SELECT COUNT(songid) FROM (SELECT songid FROM recently ORDER BY timeplayed DESC LIMIT ?) AS counter LEFT JOIN songs ON songid=id WHERE genre=?"); $sth->execute($christmasfreq - 1, $Config->{CHRISTMASGENRE}); @row = $sth->fetchrow_array(); $sth->finish(); if ( $row[0] == 0 ) { $forcechristmas = 1; } } if ( $forcechristmas ) { if ( $debug ) { print "No Christmas songs found in the last ${christmasfreq}. Forcing one to play.\n"; } $queueselect = "SELECT id FROM queues WHERE name='" . $Config->{CHRISTMASGENRE} . "'"; $sth_first = $dbh->prepare("SELECT qid, songid, CONCAT(path, song) FROM queuecontents AS qc LEFT JOIN songs ON songid=id WHERE qc.timesplayed=0 AND qid=(${queueselect}) ORDER BY RAND() LIMIT 1"); $sth_first->execute(); $numsongs = $sth_first->rows; if ( $sth_first->rows == 0 ) { $sth = $dbh->prepare("UPDATE queuecontents SET timesplayed=0 WHERE qid=(${queueselect})"); $sth->execute(); $sth->finish(); $sth_second = $dbh->prepare("SELECT qid, songid, CONCAT(path, song) FROM queuecontents AS qc LEFT JOIN songs ON songid=id WHERE qc.timesplayed=0 AND qid=(${queueselect}) ORDER BY RAND() LIMIT 1"); $sth_second->execute(); if ( $sth->rows == 1 ) { @row = $sth_second->fetchrow_array(); $qid = $row[0]; $songid = $row[1]; $song = $row[2]; } $sth_second->finish(); } else { @row = $sth_first->fetchrow_array(); $sth_first->finish(); $qid = $row[0]; $songid = $row[1]; $song = $row[2]; } } # Only try to pull from the instantq if we don't have a song yet if ( $songid == 0 ) { # if there is anything in the instantq, get the list of songs # (sorted by "id"), delete the most recent one and return # the full path to the song my $sth = $dbh->prepare("SELECT instantq.id, songid, CONCAT(path, song) AS songpath FROM instantq LEFT JOIN songs ON songid=songs.id ORDER BY id"); $sth->execute(); if ( $sth->rows > 0 ) { @result = $sth->fetchrow_array(); $sth->finish(); $id = $result[0]; $songid = $result[1]; $songpath = $result[2]; $dbh->do("DELETE FROM instantq WHERE id=$id"); $sth->finish(); return ($songid, $songpath); } $sth->finish(); } # Only try to grab the next song in the active queue if we don't have a song yet if ( $songid == 0 ) { # We wouldn't be here if there was anything in the instant queue # so let's find out the default queue and randomly select a song # from that queue which is in the group of lowest "timesplayed". # Basically, when a song in a queue is played by the autoplayer # its "timesplayed" is incremented. Each queue should have "timesplayed" # values of only two distinct numbers since each queue starts at 0 (zero), # gets incremented only when autoplayed, and won't get autoplayed again # until after all other lower number "timesplayed" have been played. if ( $debug ) { print "Trying to pull a song from the active queue.\n"; } $queueselect = "SELECT id FROM queues WHERE active='true'"; $sth_first = $dbh->prepare("SELECT qid, songid, CONCAT(path, song) FROM queuecontents AS qc LEFT JOIN songs ON songid=id WHERE qc.timesplayed=0 AND qid=(${queueselect}) ORDER BY RAND() LIMIT 1"); $sth_first->execute(); $numsongs = $sth->rows; # if there are no songs returned then reset the played count to zero and try again if ( $sth_first->rows == 0 ) { if ( $debug ) { print "Found no songs. Resetting timesplayed and trying again.\n"; } $sth = $dbh->prepare("UPDATE queuecontents SET timesplayed=0 WHERE qid=(${queueselect})"); $sth->execute(); $sth->finish(); $sth_second = $dbh->prepare("SELECT qid, songid, CONCAT(path, song) FROM queuecontents AS qc LEFT JOIN songs ON songid=id WHERE qc.timesplayed=0 AND qid=(${queueselect}) ORDER BY RAND() LIMIT 1"); $sth_second->execute(); if ( $sth_second->rows == 0 ) { if ( $debug ) { print "Found no songs after resetting timesplayed. Queue must be empty. Returning empty song.\n"; } return (0, ""); } @result = $sth_second->fetchrow_array(); $sth_second->finish(); } else { @result = $sth_first->fetchrow_array(); $sth_first->finish(); } $qid = $result[0]; $songid = $result[1]; $song = $result[2]; } # Increment the timesplayed for this song if a song was found $sound = `/usr/bin/amixer sget Master`; @mixer = split(/\n/, $sound); $muted = 1; if ( index($mixer[@mixer-1], "[on]") > 0 ) { $muted = 0; } if ( ($muted == 0) && ($songid > 0) ) { $sth = $dbh->prepare("UPDATE queuecontents SET timesplayed=1 WHERE qid=? AND songid=?"); $sth->execute($qid, $songid); $sth->finish(); } # return the song ID and the relative path return ($songid, $song); } while ( 1 ) { if ( -e "/tmp/homeaudio.stop" ) { sleep 10; next; } my ($songid, $song) = getNextSong(); # if the song is blank, sleep for 60 seconds and try again # the song might be blank if the active queue is empty # or there is no active queue and the instantq is empty # or the song that was found in the DB doesn't exist on # the hard drive if ( $song eq "" ) { if ( $debug ) { print "Found no songs to play. Sleeping for 60 seconds.\n"; } sleep 60; next; } $songcmd = $Config->{MP3DIR} . $song; $songcmd =~ s/ /\\ /g; $songcmd =~ s/&/\\&/g; $songcmd =~ s/\(/\\\(/g; $songcmd =~ s/\)/\\\)/g; $songcmd =~ s/\[/\\\[/g; $songcmd =~ s/\]/\\\]/g; $songcmd =~ s/'/\\'/g; $songcmd =~ s/"/\\"/g; $songcmd =~ s/\$/\\\$/g; $songdb = $song; $songdb =~ s/'/\\'/g; $sth = $dbh->prepare("INSERT INTO recently (songid, timeplayed) VALUES(?, NOW())"); $sth->execute($songid); $sth->finish(); $sth = $dbh->prepare("SELECT timeplayed FROM recently ORDER BY timeplayed DESC limit 1 OFFSET 1000"); $sth->execute(); if ( $sth->rows == 1 ) { @row = $sth->fetchrow_array(); $sth->finish(); $sth = $dbh->prepare("DELETE FROM recently WHERE timeplayed <= ?"); $sth->execute($row[0]); } $sth->finish(); $songcmd = "/usr/bin/mpg321 -q " . $songcmd; if ( $debug ) { print("Next: " . $songcmd . "\n"); $dbh->disconnect(); exit(); } else { system($songcmd); } } # Close the DB connection $dbh->disconnect();