From: Nick Bowler Date: Fri, 19 Jun 2020 05:01:39 +0000 (-0400) Subject: mpdreload: Protocol optimizations. X-Git-Url: https://git.draconx.ca/gitweb/mpdhacks.git/commitdiff_plain/e31f68d79d01f8a497ca1e98b3dc1a57198cfba9 mpdreload: Protocol optimizations. Try harder to send fewer commands to the MPD server. In particular: * We can submit commands to batch-load subranges from the target playlist into the play queue, then move them as a group into the final location. * We don't need to send move commands for tracks that are already in the correct final position, which helps when reloading a playlist very similar to the current play queue. * By arranging for all unwanted tracks to be shifted to the end of the play queue during the consolidation process, these can all be deleted with a single command. --- diff --git a/mpdreload.pl b/mpdreload.pl index c82353e..3a7e1a1 100755 --- a/mpdreload.pl +++ b/mpdreload.pl @@ -29,8 +29,8 @@ my $sock; # 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 { - my %matches; - my $entry; + my (%matches, %idmap, $entry); + my $pos = -1; MPD::exec("playlistinfo"); while (<$sock>) { @@ -40,13 +40,15 @@ sub get_tracks_in_play_queue { if (/^(\w+): (.*)$/) { if ($1 eq "file") { $entry = $matches{$2} //= []; + $pos++; } elsif ($1 eq "Id") { push @$entry, $2; + $idmap{$2} = $pos; } } } - return \%matches; + return (\%matches, \%idmap); } # Given an MPD playlist name, returns a reference to an array containing @@ -121,21 +123,41 @@ $sock = MPD::connect(); # Retrieve the current play queue and target play queue. MPD::run("tagtypes", "clear"); -my $current = get_tracks_in_play_queue(); +my ($current, $idmap) = get_tracks_in_play_queue(); my $target = get_playlist_files($ARGV[0]); +my $end_position = (keys %$current); +my $num_added = 0; +my $add_start; + MPD::exec("command_list_begin"); for (my $i = 0; $i < @$target; $i++) { my $f = $target->[$i]; my $id = shift @{ $current->{$f} }; + if (defined $id and defined $add_start) { + my $add_position = $end_position; + + MPD::exec("load", $ARGV[0], "$add_start:$i"); + $end_position += $i - $add_start; + MPD::exec("move", "$add_position:$end_position", "$add_start"); + + undef $add_start; + } + if (defined $id) { - MPD::exec("moveid", $id, $i); + # Try not to move tracks already in the right place. + MPD::exec("moveid", $id, $i) + if ($i != $idmap->{$id} + $num_added); } else { - MPD::exec("addid", $f, $i); + $add_start //= $i; + $num_added++; } } -# Remove any tracks left from the old play queue. -MPD::exec("deleteid", $_) foreach (map { @$_ } values %$current); +# Now all unwanted tracks from the original playqueue have been moved to the +# end and can be deleted all at once. +my $rem = ($add_start // @$target) - @$target; +MPD::exec("delete", @$target - $rem . ":") if map { @$_ } values %$current; +MPD::exec("load", $ARGV[0], "$add_start:") if defined $add_start; MPD::run("command_list_end");