Skip to content

Commit aed2cbd

Browse files
committed
Using Fisher–Yates to shuffle
1 parent de0cec4 commit aed2cbd

1 file changed

Lines changed: 38 additions & 41 deletions

File tree

  • core/src/main/java/xyz/gianlu/librespot/player

core/src/main/java/xyz/gianlu/librespot/player/Player.java

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,29 @@
11
package xyz.gianlu.librespot.player;
22

3-
import com.google.gson.JsonArray;
4-
import com.google.gson.JsonObject;
5-
import com.google.protobuf.ByteString;
63
import org.apache.log4j.Logger;
74
import org.jetbrains.annotations.NotNull;
85
import xyz.gianlu.librespot.common.Utils;
96
import xyz.gianlu.librespot.common.proto.Spirc;
107
import xyz.gianlu.librespot.core.Session;
11-
import xyz.gianlu.librespot.mercury.MercuryClient;
12-
import xyz.gianlu.librespot.mercury.MercuryRequests;
13-
import xyz.gianlu.librespot.mercury.model.TrackId;
148
import xyz.gianlu.librespot.spirc.FrameListener;
159
import xyz.gianlu.librespot.spirc.SpotifyIrc;
1610

1711
import java.io.IOException;
18-
import java.util.ArrayList;
19-
import java.util.Collections;
20-
import java.util.Iterator;
21-
import java.util.List;
12+
import java.util.*;
2213

2314
/**
2415
* @author Gianlu
2516
*/
2617
public class Player implements FrameListener, TrackHandler.Listener {
2718
private static final Logger LOGGER = Logger.getLogger(Player.class);
28-
2919
private final Session session;
3020
private final SpotifyIrc spirc;
3121
private final Spirc.State.Builder state;
3222
private final PlayerConfiguration conf;
3323
private final CacheManager cacheManager;
3424
private TrackHandler trackHandler;
3525
private TrackHandler preloadTrackHandler;
26+
private long shuffleSeed;
3627

3728
public Player(@NotNull PlayerConfiguration conf, @NotNull CacheManager.CacheConfiguration cacheConfiguration, @NotNull Session session) {
3829
this.conf = conf;
@@ -176,51 +167,57 @@ private int getPosition() {
176167
return state.getPositionMs() + diff;
177168
}
178169

170+
private static int[] getShuffleExchanges(int size, long seed) {
171+
int[] exchanges = new int[size - 1];
172+
Random rand = new Random(seed);
173+
for (int i = size - 1; i > 0; i--) {
174+
int n = rand.nextInt(i + 1);
175+
exchanges[size - 1 - i] = n;
176+
}
177+
return exchanges;
178+
}
179+
179180
private void shuffleTracks() {
181+
shuffleSeed = session.random().nextLong();
182+
180183
List<Spirc.TrackRef> tracks = new ArrayList<>(state.getTrackList());
181184
if (state.getPlayingTrackIndex() != 0) {
182185
Collections.swap(tracks, 0, state.getPlayingTrackIndex());
183186
state.setPlayingTrackIndex(0);
184187
}
185188

186-
for (int i = tracks.size(); i > 1; i--)
187-
Collections.swap(tracks, i - 1, session.random().nextInt(i - 1) + 1);
189+
int size = tracks.size() - 1;
190+
int[] exchanges = getShuffleExchanges(size, shuffleSeed);
191+
for (int i = size - 1; i > 0; i--) {
192+
int n = exchanges[size - 1 - i];
193+
Collections.swap(tracks, i, n);
194+
}
188195

189196
state.clearTrack();
190197
state.addAllTrack(tracks);
191198
}
192199

193-
private void handleShuffle() {
194-
if (state.getShuffle()) {
195-
shuffleTracks();
196-
} else {
197-
String contextUri = state.getContextUri();
198-
199-
JsonArray tracks;
200-
try {
201-
MercuryRequests.ResolvedContextWrapper context = session.mercury().sendSync(MercuryRequests.resolveContext(contextUri));
202-
tracks = context.pages().get(0).getAsJsonObject().getAsJsonArray("tracks");
203-
} catch (IOException | MercuryClient.MercuryException ex) {
204-
LOGGER.fatal("Failed requesting context!", ex);
205-
return;
206-
}
207-
208-
int num = Math.min(100, tracks.size());
209-
List<Spirc.TrackRef> rebuildState = new ArrayList<>(num);
210-
for (int i = 0; i < num; i++) {
211-
JsonObject track = tracks.get(i).getAsJsonObject();
212-
rebuildState.add(Spirc.TrackRef.newBuilder()
213-
.setGid(ByteString.copyFrom(TrackId.fromUri(track.get("uri").getAsString()).getGid()))
214-
.build());
215-
}
216-
217-
Spirc.TrackRef current = state.getTrack(state.getPlayingTrackIndex());
200+
private void unshuffleTracks() {
201+
List<Spirc.TrackRef> tracks = new ArrayList<>(state.getTrackList());
202+
if (state.getPlayingTrackIndex() != 0) {
203+
Collections.swap(tracks, 0, state.getPlayingTrackIndex());
204+
state.setPlayingTrackIndex(0);
205+
}
218206

219-
state.clearTrack();
220-
state.addAllTrack(rebuildState);
221-
state.setPlayingTrackIndex(Utils.indexOf(rebuildState, current));
207+
int size = tracks.size() - 1;
208+
int[] exchanges = getShuffleExchanges(size, shuffleSeed);
209+
for (int i = 1; i < size; i++) {
210+
int n = exchanges[size - i - 1];
211+
Collections.swap(tracks, i, n);
222212
}
223213

214+
state.clearTrack();
215+
state.addAllTrack(tracks);
216+
}
217+
218+
private void handleShuffle() {
219+
if (state.getShuffle()) shuffleTracks();
220+
else unshuffleTracks();
224221
stateUpdated();
225222
}
226223

0 commit comments

Comments
 (0)