HomeAudio/scripts/homeaudio_music.pl

197 lines
7.8 KiB
Perl
Executable File

#!/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 = $Config->{MP3PLAYER} . " -q " . $songcmd;
if ( $debug ) {
print("Next: " . $songcmd . "\n"); $dbh->disconnect(); exit();
} else {
system($songcmd);
}
}
# Close the DB connection
$dbh->disconnect();