When using the "load" command to load tracks from a stored playlist,
there is no guarantee that MPD will actually successfully load them.
This can occur, for example, if a playlist is created and then some
of the files in it are removed from the database.
Such failures are not reported directly by the protocol. The "load"
command will succeed but you just get less tracks added to the play
queue. This gets mpdreload confused as it no longer has an accurate
picture of the exact queue positions.
Solve this by querying the new queue length after tracks are loaded
from the playlist. This allows mpdreload to determine the number of
failures and adjust the expected positions accordingly.
+my $pl_current_length;
+
# Returns a hash reference mapping filenames to an array reference listing
# the queue IDs for that file in the current play queue.
sub get_tracks_in_play_queue {
# Returns a hash reference mapping filenames to an array reference listing
# the queue IDs for that file in the current play queue.
sub get_tracks_in_play_queue {
+ $pl_current_length = $pos+1;
+
return (\%matches, \%idmap);
}
return (\%matches, \%idmap);
}
my ($current, $idmap) = get_tracks_in_play_queue();
my $target = get_playlist_files($ARGV[0]);
my ($current, $idmap) = get_tracks_in_play_queue();
my $target = get_playlist_files($ARGV[0]);
-my $end_position = (keys %$current);
-my $num_added = 0;
-sub load_tracks($) {
- my ($seq) = @_;
+sub load_tracks($$) {
+ my ($seq, $dst) = @_;
+ my ($newlen, $count);
my $start = $add_start // $seq;
my $start = $add_start // $seq;
+ my $add_position = $pl_current_length;
- my $add_position = $end_position;
MPD::exec("load", $ARGV[0], "$start:$end");
MPD::exec("load", $ARGV[0], "$start:$end");
- $end_position += $end - $start;
- MPD::exec("move", "$add_position:$end_position", "$start")
- if ($add_position != $start);
+ MPD::exec("status");
+ MPD::exec("command_list_end");
+
+ while (<$sock>) {
+ last if (/^OK/);
+ die($_) if (/^ACK/);
+
+ if (/^(\w+): (.*)$/) {
+ if ($1 eq "playlistlength") {
+ $newlen = int($2);
+ }
+ }
+ }
+
+ $count = $newlen - $pl_current_length;
+
+ MPD::exec("command_list_begin");
+ if ($newlen > $pl_current_length) {
+ MPD::exec("move", "$add_position:$newlen", $dst)
+ if ($add_position != $dst);
+ }
+ $pl_current_length = $newlen;
}
MPD::exec("command_list_begin");
}
MPD::exec("command_list_begin");
+my ($num_added, $num_failed) = (0, 0);
for (my $i = 0; $i < @$target; $i++) {
my $f = $target->[$i];
my $id = shift @{ $current->{$f} };
for (my $i = 0; $i < @$target; $i++) {
my $f = $target->[$i];
my $id = shift @{ $current->{$f} };
- load_tracks($i - 1) if (defined $id and defined $add_start);
+ if (defined $id and defined $add_start) {
+ my $n = $i - $add_start;
+ my $m = load_tracks($i-1, $add_start - $num_failed);
+
+ $num_added += $m;
+ $num_failed += $n - $m;
+ }
if (defined $id) {
# Try not to move tracks already in the right place.
if (defined $id) {
# Try not to move tracks already in the right place.
- MPD::exec("moveid", $id, $i)
- if ($i != $idmap->{$id} + $num_added);
+ MPD::exec("moveid", $id, $i - $num_failed)
+ if ($i - $num_failed != $idmap->{$id} + $num_added);
} else {
$add_start //= $i;
} else {
$add_start //= $i;
}
}
# Now all unwanted tracks from the original playqueue have been moved to the
# end and can be deleted all at once.
}
}
# Now all unwanted tracks from the original playqueue have been moved to the
# end and can be deleted all at once.
-my $pos = $add_start // @$target;
+my $pos = ($add_start // @$target) - $num_failed;
MPD::exec("delete", $pos . ":") if map { @$_ } values %$current;
MPD::exec("load", $ARGV[0], "$add_start:") if defined $add_start;
MPD::run("command_list_end");
MPD::exec("delete", $pos . ":") if map { @$_ } values %$current;
MPD::exec("load", $ARGV[0], "$add_start:") if defined $add_start;
MPD::run("command_list_end");