55import xyz .gianlu .librespot .common .Utils ;
66import xyz .gianlu .librespot .common .proto .Spirc ;
77import xyz .gianlu .librespot .core .Session ;
8+ import xyz .gianlu .librespot .mercury .model .TrackId ;
9+ import xyz .gianlu .librespot .player .tracks .PlaylistProvider ;
10+ import xyz .gianlu .librespot .player .tracks .StationProvider ;
11+ import xyz .gianlu .librespot .player .tracks .TracksProvider ;
812import xyz .gianlu .librespot .spirc .FrameListener ;
913import xyz .gianlu .librespot .spirc .SpotifyIrc ;
1014
1115import java .io .IOException ;
12- import java .util .*;
1316
1417/**
1518 * @author Gianlu
@@ -18,18 +21,18 @@ public class Player implements FrameListener, TrackHandler.Listener {
1821 private static final Logger LOGGER = Logger .getLogger (Player .class );
1922 private final Session session ;
2023 private final SpotifyIrc spirc ;
21- private final Spirc . State . Builder state ;
24+ private final StateWrapper state ;
2225 private final PlayerConfiguration conf ;
2326 private final CacheManager cacheManager ;
27+ private TracksProvider tracksProvider ;
2428 private TrackHandler trackHandler ;
2529 private TrackHandler preloadTrackHandler ;
26- private long shuffleSeed = 0 ;
2730
2831 public Player (@ NotNull PlayerConfiguration conf , @ NotNull CacheManager .CacheConfiguration cacheConfiguration , @ NotNull Session session ) {
2932 this .conf = conf ;
3033 this .session = session ;
3134 this .spirc = session .spirc ();
32- this .state = initState ();
35+ this .state = new StateWrapper ( initState () );
3336
3437 try {
3538 this .cacheManager = new CacheManager (cacheConfiguration );
@@ -40,16 +43,6 @@ public Player(@NotNull PlayerConfiguration conf, @NotNull CacheManager.CacheConf
4043 spirc .addListener (this );
4144 }
4245
43- private static int [] getShuffleExchanges (int size , long seed ) {
44- int [] exchanges = new int [size - 1 ];
45- Random rand = new Random (seed );
46- for (int i = size - 1 ; i > 0 ; i --) {
47- int n = rand .nextInt (i + 1 );
48- exchanges [size - 1 - i ] = n ;
49- }
50- return exchanges ;
51- }
52-
5346 public void playPause () {
5447 handlePlayPause ();
5548 }
@@ -137,8 +130,8 @@ public void frame(@NotNull Spirc.Frame frame) {
137130 }
138131
139132 private void handlePlayPause () {
140- if (state .getStatus () == Spirc .PlayStatus .kPlayStatusPlay ) handlePause ();
141- else if (state .getStatus () == Spirc .PlayStatus .kPlayStatusPause ) handlePlay ();
133+ if (state .isStatus ( Spirc .PlayStatus .kPlayStatusPlay ) ) handlePause ();
134+ else if (state .isStatus ( Spirc .PlayStatus .kPlayStatusPause ) ) handlePlay ();
142135 }
143136
144137 private void handleSetVolume (int volume ) {
@@ -169,58 +162,34 @@ private void handleVolumeUp() {
169162 }
170163
171164 private void stateUpdated () {
172- spirc .deviceStateUpdated (state );
165+ spirc .deviceStateUpdated (state . state );
173166 }
174167
175168 private int getPosition () {
176169 int diff = (int ) (System .currentTimeMillis () - state .getPositionMeasuredAt ());
177170 return state .getPositionMs () + diff ;
178171 }
179172
180- private void shuffleTracks () {
181- shuffleSeed = session .random ().nextLong ();
182-
183- List <Spirc .TrackRef > tracks = new ArrayList <>(state .getTrackList ());
184- if (state .getPlayingTrackIndex () != 0 ) {
185- Collections .swap (tracks , 0 , state .getPlayingTrackIndex ());
186- state .setPlayingTrackIndex (0 );
187- }
188-
189- int size = tracks .size () - 1 ;
190- int [] exchanges = getShuffleExchanges (size , shuffleSeed );
191- for (int i = size - 1 ; i > 1 ; i --) {
192- int n = exchanges [size - 1 - i ];
193- Collections .swap (tracks , i , n + 1 );
194- }
195-
196- state .clearTrack ();
197- state .addAllTrack (tracks );
198- }
199-
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- }
206-
207- int size = tracks .size () - 1 ;
208- int [] exchanges = getShuffleExchanges (size , shuffleSeed );
209- for (int i = 2 ; i < size ; i ++) {
210- int n = exchanges [size - i - 1 ];
211- Collections .swap (tracks , i , n + 1 );
212- }
213-
214- state .clearTrack ();
215- state .addAllTrack (tracks );
216- }
217-
218173 private void handleShuffle () {
219174 if (state .getShuffle ()) shuffleTracks ();
220175 else unshuffleTracks ();
221176 stateUpdated ();
222177 }
223178
179+ private void shuffleTracks () {
180+ if (tracksProvider instanceof PlaylistProvider )
181+ ((PlaylistProvider ) tracksProvider ).shuffleTracks (session .random ());
182+ else
183+ LOGGER .warn ("Cannot shuffle TracksProvider: " + tracksProvider );
184+ }
185+
186+ private void unshuffleTracks () {
187+ if (tracksProvider instanceof PlaylistProvider )
188+ ((PlaylistProvider ) tracksProvider ).unshuffleTracks ();
189+ else
190+ LOGGER .warn ("Cannot unshuffle TracksProvider: " + tracksProvider );
191+ }
192+
224193 private void handleSeek (int pos ) {
225194 state .setPositionMs (pos );
226195 state .setPositionMeasuredAt (System .currentTimeMillis ());
@@ -229,10 +198,12 @@ private void handleSeek(int pos) {
229198 }
230199
231200 private void updatedTracks (@ NotNull Spirc .Frame frame ) {
232- state .setPlayingTrackIndex (frame .getState ().getPlayingTrackIndex ());
233- state .clearTrack ();
234- state .addAllTrack (frame .getState ().getTrackList ());
235- state .setContextUri (frame .getState ().getContextUri ());
201+ state .update (frame );
202+ String context = frame .getState ().getContextUri ();
203+
204+ if (context .startsWith ("spotify:station:" )) tracksProvider = new StationProvider (session , state .state , frame );
205+ else tracksProvider = new PlaylistProvider (state .state , frame );
206+
236207 state .setRepeat (frame .getState ().getRepeat ());
237208 state .setShuffle (frame .getState ().getShuffle ());
238209 if (state .getShuffle ()) shuffleTracks ();
@@ -250,9 +221,9 @@ public void finishedLoading(@NotNull TrackHandler handler, boolean play) {
250221 }
251222
252223 @ Override
253- public void loadingError (@ NotNull TrackHandler handler , @ NotNull Exception ex ) {
224+ public void loadingError (@ NotNull TrackHandler handler , @ NotNull TrackId id , @ NotNull Exception ex ) {
254225 if (handler == trackHandler ) {
255- LOGGER .fatal ("Failed loading track!" , ex );
226+ LOGGER .fatal (String . format ( "Failed loading track, gid: %s" , Utils . bytesToHex ( id . getGid ())) , ex );
256227 state .setStatus (Spirc .PlayStatus .kPlayStatusStop );
257228 stateUpdated ();
258229 } else if (handler == preloadTrackHandler ) {
@@ -272,7 +243,7 @@ public void endOfTrack(@NotNull TrackHandler handler) {
272243 @ Override
273244 public void preloadNextTrack (@ NotNull TrackHandler handler ) {
274245 if (handler == trackHandler ) {
275- Spirc . TrackRef next = state . getTrack ( getQueuedTrack (false ));
246+ TrackId next = tracksProvider . getTrackAt ( tracksProvider . getNextTrackIndex (false ));
276247
277248 preloadTrackHandler = new TrackHandler (session , cacheManager , conf , this );
278249 preloadTrackHandler .sendLoad (next , false , 0 );
@@ -287,6 +258,8 @@ private void handleLoad(@NotNull Spirc.Frame frame) {
287258 .setBecameActiveAt (System .currentTimeMillis ());
288259 }
289260
261+ LOGGER .debug (String .format ("Loading context, uri: %s" , frame .getState ().getContextUri ()));
262+
290263 updatedTracks (frame );
291264
292265 if (state .getTrackCount () > 0 ) {
@@ -304,14 +277,14 @@ private void handleLoad(@NotNull Spirc.Frame frame) {
304277 private void loadTrack (boolean play ) {
305278 if (trackHandler != null ) trackHandler .close ();
306279
307- Spirc . TrackRef ref = state . getTrack ( state . getPlayingTrackIndex () );
308- if (preloadTrackHandler != null && preloadTrackHandler .isTrack (ref )) {
280+ TrackId id = tracksProvider . getCurrentTrack ( );
281+ if (preloadTrackHandler != null && preloadTrackHandler .isTrack (id )) {
309282 trackHandler = preloadTrackHandler ;
310283 preloadTrackHandler = null ;
311284 trackHandler .sendSeek (state .getPositionMs ());
312285 } else {
313286 trackHandler = new TrackHandler (session , cacheManager , conf , this );
314- trackHandler .sendLoad (ref , play , state .getPositionMs ());
287+ trackHandler .sendLoad (id , play , state .getPositionMs ());
315288 state .setStatus (Spirc .PlayStatus .kPlayStatusLoading );
316289 }
317290
@@ -326,7 +299,7 @@ private void loadTrack(boolean play) {
326299 }
327300
328301 private void handlePlay () {
329- if (state .getStatus () == Spirc .PlayStatus .kPlayStatusPause ) {
302+ if (state .isStatus ( Spirc .PlayStatus .kPlayStatusPause ) ) {
330303 if (trackHandler != null ) trackHandler .sendPlay ();
331304 state .setStatus (Spirc .PlayStatus .kPlayStatusPlay );
332305 state .setPositionMeasuredAt (System .currentTimeMillis ());
@@ -335,7 +308,7 @@ private void handlePlay() {
335308 }
336309
337310 private void handlePause () {
338- if (state .getStatus () == Spirc .PlayStatus .kPlayStatusPlay ) {
311+ if (state .isStatus ( Spirc .PlayStatus .kPlayStatusPlay ) ) {
339312 if (trackHandler != null ) trackHandler .sendPause ();
340313 state .setStatus (Spirc .PlayStatus .kPlayStatusPause );
341314
@@ -349,7 +322,7 @@ private void handlePause() {
349322 }
350323
351324 private void handleNext () {
352- int newTrack = getQueuedTrack (true );
325+ int newTrack = tracksProvider . getNextTrackIndex (true );
353326 boolean play = true ;
354327 if (newTrack >= state .getTrackCount ()) {
355328 newTrack = 0 ;
@@ -365,26 +338,7 @@ private void handleNext() {
365338
366339 private void handlePrev () {
367340 if (getPosition () < 3000 ) {
368- List <Spirc .TrackRef > queueTracks = new ArrayList <>();
369- Iterator <Spirc .TrackRef > iter = state .getTrackList ().iterator ();
370- while (iter .hasNext ()) {
371- Spirc .TrackRef track = iter .next ();
372- if (track .getQueued ()) {
373- queueTracks .add (track );
374- iter .remove ();
375- }
376- }
377-
378- int current = state .getPlayingTrackIndex ();
379- int newIndex ;
380- if (current > 0 ) newIndex = current - 1 ;
381- else if (state .getRepeat ()) newIndex = state .getTrackCount () - 1 ;
382- else newIndex = 0 ;
383-
384- for (int i = 0 ; i < queueTracks .size (); i ++)
385- state .getTrackList ().add (newIndex + 1 + i , queueTracks .get (i ));
386-
387- state .setPlayingTrackIndex (newIndex );
341+ state .setPlayingTrackIndex (tracksProvider .getPrevTrackIndex (true ));
388342 state .setPositionMs (0 );
389343 state .setPositionMeasuredAt (System .currentTimeMillis ());
390344
@@ -397,16 +351,6 @@ private void handlePrev() {
397351 }
398352 }
399353
400- private int getQueuedTrack (boolean consume ) {
401- int current = state .getPlayingTrackIndex ();
402- if (state .getTrack (current ).getQueued ()) {
403- if (consume ) state .removeTrack (current );
404- return current ;
405- }
406-
407- return current + 1 ;
408- }
409-
410354 public interface PlayerConfiguration {
411355 @ NotNull
412356 StreamFeeder .AudioQuality preferredQuality ();
@@ -415,4 +359,69 @@ public interface PlayerConfiguration {
415359
416360 float normalisationPregain ();
417361 }
362+
363+ private class StateWrapper {
364+ private final Spirc .State .Builder state ;
365+
366+ StateWrapper (@ NotNull Spirc .State .Builder state ) {
367+ this .state = state ;
368+ }
369+
370+ @ NotNull
371+ Spirc .PlayStatus getStatus () {
372+ return state .getStatus ();
373+ }
374+
375+ void setStatus (@ NotNull Spirc .PlayStatus status ) {
376+ state .setStatus (status );
377+ }
378+
379+ boolean isStatus (@ NotNull Spirc .PlayStatus status ) {
380+ return status == getStatus ();
381+ }
382+
383+ boolean getShuffle () {
384+ return state .getShuffle ();
385+ }
386+
387+ void setShuffle (boolean shuffle ) {
388+ state .setShuffle (shuffle && (tracksProvider == null || tracksProvider .canShuffle ()));
389+ }
390+
391+ void update (@ NotNull Spirc .Frame frame ) {
392+ state .setContextUri (frame .getState ().getContextUri ());
393+ }
394+
395+ long getPositionMeasuredAt () {
396+ return state .getPositionMeasuredAt ();
397+ }
398+
399+ void setPositionMeasuredAt (long ms ) {
400+ state .setPositionMeasuredAt (ms );
401+ }
402+
403+ int getPositionMs () {
404+ return state .getPositionMs ();
405+ }
406+
407+ void setPositionMs (int pos ) {
408+ state .setPositionMs (pos );
409+ }
410+
411+ boolean getRepeat () {
412+ return state .getRepeat ();
413+ }
414+
415+ void setRepeat (boolean repeat ) {
416+ state .setRepeat (repeat && (tracksProvider == null || tracksProvider .canRepeat ()));
417+ }
418+
419+ void setPlayingTrackIndex (int i ) {
420+ state .setPlayingTrackIndex (i );
421+ }
422+
423+ int getTrackCount () {
424+ return state .getTrackCount ();
425+ }
426+ }
418427}
0 commit comments