diff --git a/Slim/Player/Playlist.pm b/Slim/Player/Playlist.pm
index d8dbea47a81..88e4a5aee0c 100644
--- a/Slim/Player/Playlist.pm
+++ b/Slim/Player/Playlist.pm
@@ -700,6 +700,50 @@ sub fischer_yates_shuffle {
}
}
+# balancedShuffle is inspired by https://engineering.atspotify.com/2014/02/28/how-to-shuffle-songs/
+# It tries to not shuffle really randomly, which often is considered "unnatural". But it distributes
+# a group's items (eg. an artist's tracks) evenly along the full list.
+# $list must be a listref of tupels, where the first element of the tuple would be the item's key
+# (eg. track ID) and the second value would be the ID of the group (eg. the artist ID)
+# see also https://codegolf.stackexchange.com/questions/198094/spotify-shuffle-music-playlist-shuffle-algorithm
+sub balancedShuffle {
+ my ($list, $sortAlphabetically) = @_;
+
+ my %grouped;
+ foreach my $item (@$list) {
+ my $group = $grouped{$item->[1]} ||= [];
+ push @$group, $item->[0];
+ }
+
+ my $count = scalar @$list;
+ my %weighed;
+
+ while (my ($group, $items) = each %grouped) {
+ my $itemsCount = scalar @$items;
+
+ # shuffle items within the group
+ fischer_yates_shuffle($items);
+
+ # define initial offset - randomize to spread across range so not all start at 0
+ my $offset = rand(1/$itemsCount)*$count;
+ my $spacer = $count / $itemsCount;
+
+ my $i = 0;
+ foreach (@$items) {
+ my $jitter = -($itemsCount/10) + rand($itemsCount/10*2);
+ $weighed{$_} = $offset + $i * $spacer + $jitter;
+ $i++;
+ }
+ }
+
+
+ my $sorter = $sortAlphabetically
+ ? sub { $weighed{$a} cmp $weighed{$b} }
+ : sub { $weighed{$a} <=> $weighed{$b} };
+
+ return [ sort $sorter keys %weighed ];
+}
+
#reshuffle - every time the playlist is modified, the shufflelist should be updated
# We also invalidate the htmlplaylist at this point
sub reshuffle {
@@ -747,8 +791,26 @@ sub reshuffle {
# 1 is shuffle by song
# 2 is shuffle by album
if (shuffle($client) == 1) {
+ if ($prefs->get('useBalancedShuffle')) {
+ main::DEBUGLOG && $log->is_debug && $log->debug("Using balanced shuffle");
+ $listRef = balancedShuffle([ map {
+ my $track = playList($client)->[$_];
+ my $artist = $track->artistName;
+
+ my $handler = Slim::Player::ProtocolHandlers->handlerForURL($track->url) if !$artist;
- fischer_yates_shuffle($listRef);
+ if ( $handler && $handler->can('getMetadataFor') && (my $meta = $handler->getMetadataFor($client, $track->url)) ) {
+ $artist = $meta->{artist};
+ }
+
+ [$_, $artist || ''];
+ } @$listRef ], 'alpha');
+
+ @{$client->shufflelist} = @$listRef;
+ }
+ else {
+ fischer_yates_shuffle($listRef);
+ }
# If we're preserving the current song
# this places it at the top of the playlist
diff --git a/Slim/Plugin/RandomPlay/HTML/EN/plugins/RandomPlay/list.html b/Slim/Plugin/RandomPlay/HTML/EN/plugins/RandomPlay/list.html
index 49f1f4ea99b..c7702a5b85d 100644
--- a/Slim/Plugin/RandomPlay/HTML/EN/plugins/RandomPlay/list.html
+++ b/Slim/Plugin/RandomPlay/HTML/EN/plugins/RandomPlay/list.html
@@ -211,14 +211,6 @@
[% END %]
-
- [% "PLUGIN_RANDOM_SHUFFLE_METHOD" | string %][% "COLON" | string %]
-
- [% "PLUGIN_RANDOM_USE_FASTER_SHUFFLE" | string %]
- [% "PLUGIN_RANDOM_USE_BALANCED_SHUFFLE" | string %]
-
-
-
[% "PLUGIN_RANDOM_BEFORE_NUM_TRACKS" | string %]
diff --git a/Slim/Plugin/RandomPlay/Mixer.pm b/Slim/Plugin/RandomPlay/Mixer.pm
index 934488fa963..f9259dbdd02 100644
--- a/Slim/Plugin/RandomPlay/Mixer.pm
+++ b/Slim/Plugin/RandomPlay/Mixer.pm
@@ -112,9 +112,9 @@ sub getIdList {
libraryId => $queryLibrary,
} );
- if ($prefs->get('useBalancedShuffle')) {
+ if (preferences('server')->get('useBalancedShuffle')) {
main::DEBUGLOG && $log->is_debug && $log->debug("Using balanced shuffle");
- $idList = balancedShuffle([ map { [$_, $results->{$_}->{'tracks.primary_artist'}] } keys %$results ]);
+ $idList = Slim::Player::Playlist::balancedShuffle([ map { [$_, $results->{$_}->{'tracks.primary_artist'}] } keys %$results ]);
}
else {
# shuffle ID list
@@ -151,47 +151,6 @@ sub getIdList {
return $idList;
}
-# balancedShuffle is inspired by https://engineering.atspotify.com/2014/02/28/how-to-shuffle-songs/
-# It tries to not shuffle really randomly, which often is considered "unnatural". But it distributes
-# a group's items (eg. an artist's tracks) evenly along the full list.
-# $list must be a listref of tupels, where the first element of the tuple would be the item's key
-# (eg. track ID) and the second value would be the ID of the group (eg. the artist ID)
-# see also https://codegolf.stackexchange.com/questions/198094/spotify-shuffle-music-playlist-shuffle-algorithm
-sub balancedShuffle {
- my ($list) = @_;
-
- my %grouped;
- foreach my $item (@$list) {
- my $group = $grouped{$item->[1]} ||= [];
- push @$group, $item->[0];
- }
-
- my $count = scalar @$list;
- my %weighed;
-
- while (my ($group, $items) = each %grouped) {
- my $itemsCount = scalar @$items;
-
- # shuffle items within the group
- Slim::Player::Playlist::fischer_yates_shuffle($items);
-
- # define initial offset - randomize to spread across range so not all start at 0
- my $offset = rand(1/$itemsCount)*$count;
- my $spacer = $count / $itemsCount;
-
- my $i = 0;
- foreach (@$items) {
- my $jitter = -($itemsCount/10) + rand($itemsCount/10*2);
- $weighed{$_} = $offset + $i * $spacer + $jitter;
- $i++;
- }
- }
-
- return [ sort {
- $weighed{$a} <=> $weighed{$b}
- } keys %weighed ];
-}
-
sub getRandomYear {
my $client = shift;
my $filteredGenres = shift;
diff --git a/Slim/Plugin/RandomPlay/Plugin.pm b/Slim/Plugin/RandomPlay/Plugin.pm
index 73620aac1e8..f164b2a7faf 100644
--- a/Slim/Plugin/RandomPlay/Plugin.pm
+++ b/Slim/Plugin/RandomPlay/Plugin.pm
@@ -183,10 +183,6 @@ sub initPlugin {
[1, 1, 0, \&chooseLibrariesMenu]);
Slim::Control::Request::addDispatch(['randomplaychooselibrary', '_library'],
[1, 0, 0, \&chooseLibrary]);
- Slim::Control::Request::addDispatch(['randomplayshufflemethodlist', '_index', '_quantity'],
- [1, 0, 0, \&chooseShuffleMethod]);
- Slim::Control::Request::addDispatch(['randomplayshufflemethod', '_value'],
- [1, 0, 0, \&shuffleMethod]);
Slim::Control::Request::addDispatch(['randomplaygenreselectall', '_value'],
[1, 0, 0, \&genreSelectAllOrNone]);
Slim::Control::Request::addDispatch(['randomplayisactive'],
@@ -298,19 +294,6 @@ sub initPlugin {
},
},
},
- {
- stringToken => 'PLUGIN_RANDOM_SHUFFLE_METHOD',
- id => 'randomshufflemethod',
- weight => 65,
- window => { titleStyle => 'random' },
- node => 'randomplay',
- actions => {
- go => {
- player => 0,
- cmd => [ 'randomplayshufflemethodlist' ],
- },
- },
- },
{
stringToken => 'PLUGIN_RANDOM_DISABLE',
id => 'randomdisable',
@@ -355,10 +338,6 @@ sub initPlugin {
{ title => '{PLUGIN_RANDOM_YEAR}', url => 'randomplay://year' },
]
);
-
- $prefs->init({
- useBalancedShuffle => sub { Slim::Utils::OSDetect->getOS()->canDBHighMem() ? 1 : 0 },
- });
}
sub postinitPlugin {
@@ -631,55 +610,6 @@ sub chooseLibrariesMenu {
Slim::Control::Jive::sliceAndShip($request, $client, \@menu);
}
-sub shuffleMethod {
- my $request = shift;
-
- if (!$initialized) {
- $request->setStatusBadConfig();
- return;
- }
-
- $prefs->set('useBalancedShuffle', $request->getParam('_value') ? 1 : 0);
-
- $request->setStatusDone();
-}
-
-sub chooseShuffleMethod {
- my $request = shift;
-
- if (!$initialized) {
- $request->setStatusBadConfig();
- return;
- }
-
- my $client = $request->client();
-
- my $useBalancedShuffle = $prefs->get('useBalancedShuffle');
-
- my @menu = ({
- text => cstring($client, 'PLUGIN_RANDOM_USE_FASTER_SHUFFLE'),
- radio => ($useBalancedShuffle ? 0 : 1),
- actions => {
- 'do' => {
- player => 0,
- cmd => ['randomplayshufflemethod', 0],
- },
- },
- },{
- text => cstring($client, 'PLUGIN_RANDOM_USE_BALANCED_SHUFFLE'),
- radio => ($useBalancedShuffle ? 1 : 0),
- actions => {
- 'do' => {
- player => 0,
- cmd => ['randomplayshufflemethod', 1],
- },
- },
- });
-
- Slim::Control::Jive::sliceAndShip($request, $client, \@menu);
-}
-
-
# Returns a hash whose keys are the genres in the db
sub getGenres {
my ($client, $useIncludeGenres) = @_;
@@ -1209,7 +1139,6 @@ sub handleWebList {
$params->{'pluginRandomContinuousMode'}= $prefs->get('continuous');
$params->{'pluginRandomNowPlaying'} = $client->master->pluginData('type');
$params->{'pluginRandomUseLibrary'} = $prefs->get('library');
- $params->{'useBalancedShuffle'} = $prefs->get('useBalancedShuffle');
$params->{'mixTypes'} = \@mixTypes;
$params->{'favorites'} = {};
@@ -1258,7 +1187,6 @@ sub handleWebSettings {
$prefs->set('oldtracks', $params->{'numOldTracks'});
$prefs->set('continuous', $params->{'continuousMode'} ? 1 : 0);
$prefs->set('library', $params->{'useLibrary'});
- $prefs->set('useBalancedShuffle', $params->{'useBalancedShuffle'} ? 1 : 0);
# Pass on to check if the user requested a new mix as well
handleWebMix($client, $params);
diff --git a/Slim/Plugin/RandomPlay/strings.txt b/Slim/Plugin/RandomPlay/strings.txt
index 09b29802612..ef6158f7e1c 100644
--- a/Slim/Plugin/RandomPlay/strings.txt
+++ b/Slim/Plugin/RandomPlay/strings.txt
@@ -344,18 +344,6 @@ PLUGIN_RANDOM_LIBRARY_FILTER
NL Gebruik deelcollectie
NO Bruk delbiblioteker
-PLUGIN_RANDOM_SHUFFLE_METHOD
- DE Mischmethode
- EN Shuffle method
-
-PLUGIN_RANDOM_USE_BALANCED_SHUFFLE
- DE Ausbalancierter, aber langsamer mischen
- EN Use more balanced, but slower shuffle
-
-PLUGIN_RANDOM_USE_FASTER_SHUFFLE
- DE Schneller, aber weniger ausbalanciert mischen
- EN Use faster, but less balanced shuffle
-
PLUGIN_RANDOM_CHOOSE_BELOW
CS Vybrat náhodně zvolený mix hudby z vaší knihovny:
DA Vælg en tilfældig blanding af musik fra dit bibliotek:
diff --git a/Slim/Utils/Prefs.pm b/Slim/Utils/Prefs.pm
index a8dd92fdd54..3cdfd0786e1 100644
--- a/Slim/Utils/Prefs.pm
+++ b/Slim/Utils/Prefs.pm
@@ -214,6 +214,7 @@ sub init {
'precacheArtwork' => 1,
'customArtSpecs' => {},
'maxPlaylistLength' => sub { $os->canDBHighMem() ? 2500 : 500 },
+ 'useBalancedShuffle' => sub { $os->canDBHighMem() ? 1 : 0 },
# Server Settings - Security
'filterHosts' => 0,
'allowedHosts' => sub {
diff --git a/Slim/Web/Settings/Server/Performance.pm b/Slim/Web/Settings/Server/Performance.pm
index bdba3b69253..f7729ec3b57 100644
--- a/Slim/Web/Settings/Server/Performance.pm
+++ b/Slim/Web/Settings/Server/Performance.pm
@@ -22,7 +22,7 @@ sub page {
}
sub prefs {
- my @prefs = ( $prefs, qw(dbhighmem disableStatistics serverPriority scannerPriority
+ my @prefs = ( $prefs, qw(dbhighmem disableStatistics serverPriority scannerPriority useBalancedShuffle
precacheArtwork maxPlaylistLength useLocalImageproxy dontTriggerScanOnPrefChange) );
push @prefs, qw(autorescan autorescan_stat_interval) if Slim::Utils::OSDetect::getOS->canAutoRescan;
return @prefs;
diff --git a/strings.txt b/strings.txt
index cde1a00a8aa..565e7c3dca4 100644
--- a/strings.txt
+++ b/strings.txt
@@ -8426,7 +8426,7 @@ SETUP_ENHANCEDHTTP_DESC
SETUP_ENABLE_PERSISTENTHTTP
EN Persistent mode
FR Mode persistent
-
+
SETUP_ENABLE_BUFFEREDHTTP
DE HTTP(S) Datenströme zwischenspeichern
EN Cache HTTP(S) streams on disk
@@ -19334,6 +19334,18 @@ SETUP_SERVERPRIORITY
SV Serverprioritet
ZH_CN Logitech Media Server服务器流程优先值
+SETUP_SHUFFLE_METHOD
+ DE Mischmethode
+ EN Shuffle method
+
+SETUP_USE_BALANCED_SHUFFLE
+ DE Ausbalancierter, aber langsamer mischen
+ EN Use more balanced, but slower shuffle
+
+SETUP_USE_FASTER_SHUFFLE
+ DE Schneller, aber weniger ausbalanciert mischen
+ EN Use faster, but less balanced shuffle
+
SETUP_SERVERPRIORITY_DESC
CS Můžete zadat prioritu pro Logitech Media Server.
DA Du kan specificere hvilken prioritet Logitech Media Server skal have.