X-Git-Url: https://git.ktnx.net/?a=blobdiff_plain;f=bin%2Fmpd-feeder;h=d553ea3e1d885980f1d851a11da7a45d4688112f;hb=21db1abac627d6ad57487915d21fbd2798df2e4c;hp=ee17eda89eb191dc44694441e3f3c00c7b28a118;hpb=a2a01d4c16fdfcf80a887a648a9b489d2ee704fa;p=mpd-feeder.git diff --git a/bin/mpd-feeder b/bin/mpd-feeder index ee17eda..d553ea3 100755 --- a/bin/mpd-feeder +++ b/bin/mpd-feeder @@ -4,11 +4,12 @@ use v5.32; use Getopt::Long (); use Log::Any qw($log); -use Log::Any::Adapter Stderr => log_level => 'trace'; +use Log::Any::Adapter Stderr => log_level => 'error'; use Object::Pad; use Syntax::Keyword::Try; class Options { + use Log::Any qw($log); use Time::Duration qw(duration_exact); use Time::Duration::Parse qw(parse_duration); has $log_level :reader = 'warn'; @@ -27,12 +28,14 @@ class Options { Getopt::Long::GetOptions( 'log-level=s' => \$log_level, 'skip-db-update!' => \$skip_db_update, - 'tql|target-queue-length=n' => \$target_queue_length, - 'mpd-host=s' => \$mpd_host, - 'mpd-port=s' => \$mpd_port, - 'db-path=s' => \$db_path, - 'db-user=s' => \$db_user, - 'min-album-interval=s' => sub { + 'tql|target-queue-length=n' => sub { + $target_queue_length = parse_integer(pop); + }, + 'mpd-host=s' => \$mpd_host, + 'mpd-port=s' => \$mpd_port, + 'db-path=s' => \$db_path, + 'db-user=s' => \$db_user, + 'min-album-interval=s' => sub { $min_album_interval = parse_duration(pop); }, 'min-sing-interval=s' => sub { @@ -54,6 +57,8 @@ class Options { $value = $converter->($value) if $converter; $$target_ref = $value; + + $log->trace("Option $section.$option = $value"); } method dump { @@ -63,7 +68,6 @@ class Options { say "[mpd]"; say "host = " . ( $mpd_host // '' ); say "port = " . ( $mpd_port // '' ); - say "target-queue-length = $target_queue_length"; say ""; say "[queue]"; say "target-length = $target_queue_length"; @@ -77,7 +81,14 @@ class Options { say "password = " . ( $db_password // '' ); } + sub parse_integer($input) { + die "Invalid integer value '$input'" unless $input =~ /^\+?\d{1,18}$/; + return $input + 0; + } + method parse_config_file($path) { + $log->trace("Parsing configuration file $path"); + use Config::INI::Reader; my $ini = Config::INI::Reader->read_file($path); @@ -87,7 +98,9 @@ class Options { handle_config_option( $ini => 'mpd-feeder' => log_level => \$log_level ); handle_config_option( - $ini => queue => 'target-length' => \$target_queue_length ); + $ini => queue => 'target-length' => \$target_queue_length, + \&parse_integer + ); handle_config_option( $ini => queue => 'min-song-interval' => \$min_song_interval, \&parse_duration @@ -110,6 +123,7 @@ class Options { } class Feeder { + has $cfg_file :reader; has $opt :reader; has $db; has $db_generation; @@ -121,27 +135,31 @@ use constant DEFAULT_CONFIG_FILE => '/etc/mpd-feeder/mpd-feeder.conf'; use DBD::Pg; use DBI; use Log::Any qw($log); +use IO::Async::Signal; use Net::Async::MPD; ADJUST { - $opt = Options->new; + Getopt::Long::Configure('pass_through'); + Getopt::Long::GetOptions('cfg|config=s' => \$cfg_file); + Getopt::Long::Configure('no_pass_through'); - { - my $cfg_file; - Getopt::Long::Configure('pass_through'); - Getopt::Long::GetOptions('cfg|config=s' => \$cfg_file); - Getopt::Long::Configure('no_pass_through'); + $cfg_file //= DEFAULT_CONFIG_FILE if -e DEFAULT_CONFIG_FILE; - $cfg_file //= DEFAULT_CONFIG_FILE if -e DEFAULT_CONFIG_FILE; + $self->configure; - $opt->parse_config_file($cfg_file) if $cfg_file; - } + $db_needs_update = 0 if $opt->skip_db_update; + } - $opt->parse_command_line; + method configure { + my $new_opt = Options->new; - $db_needs_update = 0 if $opt->skip_db_update; + $new_opt->parse_config_file($cfg_file) if $cfg_file; + + $new_opt->parse_command_line; + + Log::Any::Adapter->set( Stderr => log_level => $new_opt->log_level ); - Log::Any::Adapter->set( Stderr => log_level => $opt->log_level ); + $opt = $new_opt; } method connect_mpd { @@ -152,6 +170,32 @@ use Net::Async::MPD; $conn{port} = $opt->mpd_port if $opt->mpd_port; $mpd = Net::Async::MPD->new(%conn); + + $mpd->loop->add( + IO::Async::Signal->new( + name => 'HUP', + on_receipt => sub { + $log->debug("SIGHUP received. Stopping loop"); + $mpd->loop->stop('reload'); + }, + ) + ); + + $mpd->loop->add( + IO::Async::Signal->new( + name => 'USR1', + on_receipt => sub { + $log->debug("SIGUSR1 received. Dumping configuration to STDERR"); + my $old = select \*STDERR; + try { + $opt->dump; + } + finally { + select $old; + } + }, + ) + ); } method connect_db { @@ -255,7 +299,7 @@ SQL foreach my $entry (@$rows) { next unless exists $entry->{file}; $self->db_store_song( $entry->{file}, - $entry->{Artist}, $entry->{Album} ); + $entry->{AlbumArtist}, $entry->{Album} ); $song_count++; } @@ -355,7 +399,8 @@ SQL sub { my $present = scalar @{ $_[0] }; - $log->notice("Playlist contains $present songs"); + $log->notice( "Playlist contains $present songs. Wanted: " + . $opt->target_queue_length ); if ( $present < $opt->target_queue_length ) { $self->queue_songs( $opt->target_queue_length - $present, $callback ); @@ -401,7 +446,6 @@ SQL $f->on_fail( sub { die @_ } ); $f->on_done( sub { - warn $_ for @_; $self->db_note_song_qeued($_) for @list; $callback->(@_) if $callback; } @@ -412,7 +456,6 @@ SQL $log->trace('declaring idle mode'); $mpd->send('idle database playlist')->on_done( sub { - warn $_ for @_; my $result = shift; if ( $result->{changed} eq 'database' ) { @@ -442,6 +485,25 @@ SQL $self->prepare_to_wait_idle; } + + method stop { + undef $mpd; + + if ($db) { + if ($db->{ActiveKids}) { + $log->warn("$db->{ActiveKids} active DB statements"); + for my $st ( @{ $db->{ChildHandles} } ) { + next unless $st->{Active}; + while(my($k,$v) = each %$st) { + $log->debug("$k = ".($v//'')); + } + } + } + + $db->disconnect; + undef $db; + } + } } my $feeder = Feeder->new(); @@ -505,6 +567,18 @@ if (@ARGV) { } } -$feeder->queue_songs( undef, sub { $feeder->run } ); +for ( ;; ) { + $feeder->queue_songs( undef, sub { $feeder->run } ); + + $log->debug("Entering event loop. PID=$$"); + + my $result = $feeder->mpd->loop->run; + $log->trace( "Got loop result of " . ( $result // 'undef' ) ); -$feeder->mpd->loop->run; + if ('reload' eq $result) { + $log->notice("disconnecting"); + $feeder->stop; + + exec( "$0", '--config', $feeder->cfg_file, '--skip-db-update' ); + } +}