has $verbose :reader = 0;
has $single :reader = 0;
has $one_shot :reader = 0;
+ has $skip_db_update :reader = 0;
has $dump_config :reader = 0;
method verb($message) {
'dump-config!' => \$dump_config,
's|single!' => \$single,
'one-shot!' => \$one_shot,
+ 'skip-db-update!' => \$skip_db_update,
'tql|target-queue-length=n' => \$target_queue_length,
'mpd-host=s' => \$mpd_host,
'mpd-port=s' => \$mpd_port,
has $opt :reader;
has $db;
has $db_generation;
- has $mpd;
+ has $mpd :reader;
use constant DEFAULT_CONFIG_FILE => '/etc/mpd-feeder/mpd-feeder.conf';
+use DBD::Pg;
+use DBI;
+use Net::Async::MPD;
ADJUST {
$opt = Options->new;
$opt->parse_command_line;
unless ($opt->dump_config) {
- $mpd = Net::Async::MPD->new(
- host => $opt->mpd_host,
- port => $opt->mpd_port,
- auto_connect => 1,
- );
+ my %conn = ( auto_connect => 1 );
+ $conn{host} = $opt->mpd_host if $opt->mpd_host;
+ $conn{port} = $opt->mpd_port if $opt->mpd_port;
+
+ $mpd = Net::Async::MPD->new(%conn);
$self->connect_db;
- $self->update_db;
+ $self->update_db unless $self->opt->skip_db_update;
}
}
method connect_db {
return if $db;
- $db = DBI->connect( "dbi:" . $opt->db_path,
+ $db =
+ DBI->connect( "dbi:Pg:dbname=" . $opt->db_path,
$opt->db_user, $opt->db_password,
{ RaiseError => 1, AutoCommit => 1 } );
$db->prepare_cached(
<<'SQL')->execute( $song, $artist, $album, $db_generation );
INSERT INTO songs(path, artist, album, generation)
-VALUES($1, $2, $3, $3)
+VALUES($1, $2, $3, $4)
ON CONFLICT ON CONSTRAINT songs_pkey DO
UPDATE SET artist = $2
, album = $3
$mpd->send('listallinfo')->on_done(
sub {
try {
- $db->begin;
+ my $rows = shift;
+ $db->begin_work;
$db_generation++;
- my ($song, $artist, $album);
-
- foreach my $row (@_) {
- chomp($row);
-
- if ($row =~ s/^file:\s*//) {
- $self->db_store_song( $song, $artist, $album );
- $song = $row;
- $artist = $album = undef;
- }
- elsif ( $row =~ s/^Artist:\s*// ) {
- $artist = $row;
- }
- elsif ( $row =~ s/^Album:\s*// ) {
- $album = $row;
- }
+ my $song_count;
+
+ foreach my $entry (@$rows) {
+ next unless exists $entry->{file};
+ $self->db_store_song( $entry->{file},
+ $entry->{Artist}, $entry->{Album} );
+ $song_count++;
}
$self->db_store_song($song, $artist, $album);
method db_find_suitable_songs($num) {
my @result;
- my $sth = $self->db->prepare_cached(<<SQL);
+ my $sth = $db->prepare_cached(<<SQL);
SELECT s.path, s.artist, s.album
FROM songs s
JOIN artists ar ON ar.artist=s.artist
JOIN albums al ON al.album=s.album
-WHERE (s.last_queued IS NULL OR s.last_queued < CURRENT_TIMESTAMP - CAST(? AS float))
- AND (ar.last_queued IS NULL OR ar.last_queued < CURRENT_TIMESTAMP - CAST(? AS float))
- AND (al.last_queued IS NULL OR al.last_queued < CURRENT_TIMESTAMP - CAST(? AS float))
+WHERE (s.last_queued IS NULL OR s.last_queued < CURRENT_TIMESTAMP - (? || ' seconds')::interval)
+ AND (ar.last_queued IS NULL OR ar.last_queued < CURRENT_TIMESTAMP - (? || ' seconds')::interval)
+ AND (al.last_queued IS NULL OR al.last_queued < CURRENT_TIMESTAMP - (? || ' seconds')::interval)
AND NOT EXISTS (SELECT 1 FROM blacklisted_artists bar WHERE bar.artist = s.artist)
AND NOT EXISTS (SELECT 1 FROM blacklisted_albums bal WHERE bal.album = s.album)
ORDER BY random()
LIMIT ?
SQL
$sth->execute(
- $self->opt->min_song_interval / 3600.0 / 24.0,
- $self->opt->min_artist_interval / 3600.0 / 24.0,
- $self->opt->min_album_interval / 3600.0 / 24.0,
+ $self->opt->min_song_interval,
+ $self->opt->min_artist_interval,
+ $self->opt->min_album_interval,
$num,
);
while ( my @row = $sth->fetchrow_array ) {