Skip to content

Commit a3dccea

Browse files
committed
Moved next/prev logic to StateWrapper
1 parent 640d4b7 commit a3dccea

3 files changed

Lines changed: 153 additions & 132 deletions

File tree

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

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,9 @@ private void handleFrame(@NotNull Spirc.MessageType type, @NotNull Spirc.Frame s
157157
case kMessageTypeAction:
158158
if (frame == null) break;
159159

160-
switch (frame.endpoint) {
161-
case SetRepeatingTrack:
162-
state.setRepeatingTrack(frame.value.getAsBoolean());
163-
break;
160+
if (frame.endpoint == Remote3Frame.Endpoint.SetRepeatingTrack) {
161+
state.setRepeatingTrack(frame.value.getAsBoolean());
162+
state.updated();
164163
}
165164
break;
166165
}
@@ -303,9 +302,8 @@ public void endOfTrack(@NotNull TrackHandler handler) {
303302
@Override
304303
public void preloadNextTrack(@NotNull TrackHandler handler) {
305304
if (handler == trackHandler && state.hasProvider()) {
306-
int index = state.getNextTrackIndex(false);
307-
if (index < state.getTrackCount()) {
308-
PlayableId next = state.getTrackAt(index);
305+
PlayableId next = state.nextPlayableDoNotSet();
306+
if (next != null) {
309307
preloadTrackHandler = new TrackHandler(session, lines, conf, this);
310308
preloadTrackHandler.sendLoad(next, false, 0);
311309
LOGGER.trace("Started next track preload, gid: " + Utils.bytesToHex(next.getGid()));
@@ -381,17 +379,13 @@ private void handleLoad(@NotNull Remote3Frame frame) {
381379
return;
382380
}
383381

384-
if (state.getTrackCount() > 0) {
385-
state.setPositionMs(frame.options.seekTo == -1 ? 0 : frame.options.seekTo);
386-
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());
382+
state.setPositionMs(frame.options.seekTo == -1 ? 0 : frame.options.seekTo);
383+
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());
387384

388-
boolean play;
389-
if (frame.options.initiallyPaused != null) play = !frame.options.initiallyPaused;
390-
else play = !wasInactive;
391-
loadTrack(play);
392-
} else {
393-
panicState();
394-
}
385+
boolean play;
386+
if (frame.options.initiallyPaused != null) play = !frame.options.initiallyPaused;
387+
else play = !wasInactive;
388+
loadTrack(play);
395389
}
396390

397391
private void loadTrack(boolean play) {
@@ -444,28 +438,19 @@ private void handlePause() {
444438
private void handleNext() {
445439
if (!state.hasProvider()) return;
446440

447-
int newTrack = state.getNextTrackIndex(true);
448-
boolean play = true;
449-
if (newTrack >= state.getTrackCount()) {
450-
if (state.getRepeat()) {
451-
newTrack = 0;
452-
play = true;
453-
} else {
454-
if (conf.autoplayEnabled()) {
455-
loadAutoplay();
456-
return;
457-
} else {
458-
newTrack = 0;
459-
play = false;
460-
}
461-
}
441+
StateWrapper.NextPlayable next = state.nextPlayable(conf);
442+
if (next == StateWrapper.NextPlayable.AUTOPLAY) {
443+
loadAutoplay();
444+
return;
462445
}
463446

464-
state.setPlayingTrackIndex(newTrack);
465-
state.setPositionMs(0);
466-
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());
467-
468-
loadTrack(play);
447+
if (next.isOk()) {
448+
state.setPositionMs(0);
449+
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());
450+
loadTrack(next == StateWrapper.NextPlayable.OK_PLAY);
451+
} else {
452+
LOGGER.fatal("Failed loading next song: " + next);
453+
}
469454
}
470455

471456
private void loadAutoplay() {
@@ -513,11 +498,14 @@ private void handlePrev() {
513498
if (!state.hasProvider()) return;
514499

515500
if (getPosition() < 3000) {
516-
state.setPlayingTrackIndex(state.getPrevTrackIndex());
517-
state.setPositionMs(0);
518-
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());
519-
520-
loadTrack(true);
501+
StateWrapper.PreviousPlayable prev = state.previousPlayable();
502+
if (prev.isOk()) {
503+
state.setPositionMs(0);
504+
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());
505+
loadTrack(true);
506+
} else {
507+
LOGGER.fatal("Failed loading previous song: " + prev);
508+
}
521509
} else {
522510
state.setPositionMs(0);
523511
state.setPositionMeasuredAt(TimeProvider.currentTimeMillis());

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

Lines changed: 118 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -65,67 +65,12 @@ String getContextUri() {
6565
return state.getContextUri();
6666
}
6767

68-
@NotNull
69-
private Spirc.PlayStatus getStatus() {
70-
return state.getStatus();
71-
}
72-
7368
void setStatus(@NotNull Spirc.PlayStatus status) {
7469
state.setStatus(status);
7570
}
7671

7772
boolean isStatus(@NotNull Spirc.PlayStatus status) {
78-
return status == getStatus();
79-
}
80-
81-
void setShuffle(boolean shuffle) {
82-
state.setShuffle(shuffle && (playablesProvider == null || playablesProvider.canShuffle()));
83-
if (state.getShuffle()) shuffleContent(false);
84-
else unshuffleContent();
85-
}
86-
87-
private void loadPlayablesProvider(@NotNull String uri) throws SpotifyContext.UnsupportedContextException {
88-
SpotifyContext context = SpotifyContext.from(uri);
89-
playablesProvider = context.initProvider(session, state);
90-
}
91-
92-
private void shuffleContent(boolean fully) {
93-
if (playablesProvider == null) return;
94-
95-
if (playablesProvider.canShuffle() && playablesProvider instanceof ShuffleableProvider)
96-
((ShuffleableProvider) playablesProvider).shuffleContent(session.random(), fully);
97-
else
98-
LOGGER.warn("Cannot shuffle provider: " + playablesProvider);
99-
}
100-
101-
private void unshuffleContent() {
102-
if (playablesProvider == null) return;
103-
104-
if (playablesProvider.canShuffle() && playablesProvider instanceof ShuffleableProvider)
105-
((ShuffleableProvider) playablesProvider).unshuffleContent();
106-
else
107-
LOGGER.warn("Cannot unshuffle provider: " + playablesProvider);
108-
}
109-
110-
void updated() {
111-
session.spirc().deviceStateUpdated(state);
112-
}
113-
114-
void seekTo(@Nullable String uri) {
115-
int pos = -1;
116-
List<Spirc.TrackRef> tracks = state.getTrackList();
117-
for (int i = 0; i < tracks.size(); i++) {
118-
Spirc.TrackRef track = tracks.get(i);
119-
if (track.getUri().equals(uri)) {
120-
pos = i;
121-
break;
122-
}
123-
}
124-
125-
if (pos == -1)
126-
pos = 0;
127-
128-
state.setPlayingTrackIndex(pos);
73+
return status == state.getStatus();
12974
}
13075

13176
long getPositionMeasuredAt() {
@@ -144,31 +89,32 @@ void setPositionMs(int pos) {
14489
state.setPositionMs(pos);
14590
}
14691

147-
boolean getRepeat() {
148-
return state.getRepeat();
149-
}
150-
15192
void setRepeat(boolean repeat) {
15293
state.setRepeat(repeat && (playablesProvider == null || playablesProvider.canRepeat()));
15394
}
15495

155-
void setPlayingTrackIndex(int i) {
156-
state.setPlayingTrackIndex(i);
96+
void setShuffle(boolean shuffle) {
97+
state.setShuffle(shuffle && (playablesProvider == null || playablesProvider.canShuffle()));
98+
if (state.getShuffle()) shuffleContent(false);
99+
else unshuffleContent();
157100
}
158101

159-
int getTrackCount() {
160-
return state.getTrackCount();
161-
}
102+
private void shuffleContent(boolean fully) {
103+
if (playablesProvider == null) return;
162104

163-
void loadStation(@NotNull MercuryRequests.StationsWrapper station) throws SpotifyContext.UnsupportedContextException {
164-
state.setContextUri(station.uri());
105+
if (playablesProvider.canShuffle() && playablesProvider instanceof ShuffleableProvider)
106+
((ShuffleableProvider) playablesProvider).shuffleContent(session.random(), fully);
107+
else
108+
LOGGER.warn("Cannot shuffle provider: " + playablesProvider);
109+
}
165110

166-
state.clearTrack();
167-
state.addAllTrack(station.tracks());
168-
state.setPlayingTrackIndex(0);
169-
SpotifyIrc.trimTracks(state);
111+
private void unshuffleContent() {
112+
if (playablesProvider == null) return;
170113

171-
loadPlayablesProvider(station.uri());
114+
if (playablesProvider.canShuffle() && playablesProvider instanceof ShuffleableProvider)
115+
((ShuffleableProvider) playablesProvider).unshuffleContent();
116+
else
117+
LOGGER.warn("Cannot unshuffle provider: " + playablesProvider);
172118
}
173119

174120
private int lastQueuedSongIndex() {
@@ -185,6 +131,13 @@ private int lastQueuedSongIndex() {
185131
return lastQueued;
186132
}
187133

134+
private void loadPlayablesProvider(@NotNull String uri) throws SpotifyContext.UnsupportedContextException {
135+
if (state.getTrackCount() == 0) throw SpotifyContext.UnsupportedContextException.empty();
136+
137+
SpotifyContext context = SpotifyContext.from(uri);
138+
playablesProvider = context.initProvider(session, state);
139+
}
140+
188141
@NotNull
189142
private List<Remote3Page> getPages(@NotNull Remote3Frame.Context context) throws IOException, MercuryClient.MercuryException {
190143
MercuryRequests.ResolvedContextWrapper resolved = session.mercury().sendSync(MercuryRequests.resolveContext(context.uri));
@@ -200,15 +153,6 @@ private List<Remote3Track> getTracks(@NotNull String pageUrl) throws IOException
200153
return Remote3Track.array(obj.getAsJsonArray("tracks"));
201154
}
202155

203-
void loadFromUri(@NotNull String context) throws IOException, MercuryClient.MercuryException, SpotifyContext.UnsupportedContextException {
204-
state.setContextUri(context);
205-
state.clearTrack();
206-
207-
MercuryRequests.ResolvedContextWrapper resolved = session.mercury().sendSync(MercuryRequests.resolveContext(context));
208-
loadPage(resolved.pages().get(0), null);
209-
loadPlayablesProvider(context);
210-
}
211-
212156
private void loadPage(@NotNull Remote3Page page, @Nullable TrackSelector selector) throws IOException {
213157
List<Remote3Track> tracks = page.tracks;
214158
if (tracks == null) {
@@ -231,6 +175,47 @@ private void loadPage(@NotNull Remote3Page page, @Nullable TrackSelector selecto
231175
if (state.getShuffle()) shuffleContent(selector == null || !selector.findMatch());
232176
}
233177

178+
void updated() {
179+
session.spirc().deviceStateUpdated(state);
180+
}
181+
182+
void seekTo(@Nullable String uri) {
183+
int pos = -1;
184+
List<Spirc.TrackRef> tracks = state.getTrackList();
185+
for (int i = 0; i < tracks.size(); i++) {
186+
Spirc.TrackRef track = tracks.get(i);
187+
if (track.getUri().equals(uri)) {
188+
pos = i;
189+
break;
190+
}
191+
}
192+
193+
if (pos == -1)
194+
pos = 0;
195+
196+
state.setPlayingTrackIndex(pos);
197+
}
198+
199+
void loadStation(@NotNull MercuryRequests.StationsWrapper station) throws SpotifyContext.UnsupportedContextException {
200+
state.setContextUri(station.uri());
201+
202+
state.clearTrack();
203+
state.addAllTrack(station.tracks());
204+
state.setPlayingTrackIndex(0);
205+
SpotifyIrc.trimTracks(state);
206+
207+
loadPlayablesProvider(station.uri());
208+
}
209+
210+
void loadFromUri(@NotNull String context) throws IOException, MercuryClient.MercuryException, SpotifyContext.UnsupportedContextException {
211+
state.setContextUri(context);
212+
state.clearTrack();
213+
214+
MercuryRequests.ResolvedContextWrapper resolved = session.mercury().sendSync(MercuryRequests.resolveContext(context));
215+
loadPage(resolved.pages().get(0), null);
216+
loadPlayablesProvider(context);
217+
}
218+
234219
void load(@NotNull Remote3Frame frame) throws IOException, MercuryClient.MercuryException, SpotifyContext.UnsupportedContextException {
235220
if (frame.context == null) throw new IllegalArgumentException("Missing context object!");
236221

@@ -348,22 +333,65 @@ boolean hasProvider() {
348333
return playablesProvider != null;
349334
}
350335

351-
int getPrevTrackIndex() {
352-
return playablesProvider.getPrevTrackIndex();
336+
@NotNull
337+
PlayableId getCurrentTrack() {
338+
return playablesProvider.getCurrentTrack();
353339
}
354340

355-
int getNextTrackIndex(boolean consume) {
356-
return playablesProvider.getNextTrackIndex(consume);
341+
@NotNull
342+
StateWrapper.NextPlayable nextPlayable(@NotNull Player.Configuration conf) {
343+
if (playablesProvider == null) return NextPlayable.MISSING_PROVIDER;
344+
345+
int newTrack = playablesProvider.getNextTrackIndex(true);
346+
boolean play = true;
347+
if (newTrack >= state.getTrackCount()) {
348+
if (state.getRepeat()) {
349+
newTrack = 0;
350+
play = true;
351+
} else {
352+
if (conf.autoplayEnabled()) {
353+
return NextPlayable.AUTOPLAY;
354+
} else {
355+
newTrack = 0;
356+
play = false;
357+
}
358+
}
359+
}
360+
361+
state.setPlayingTrackIndex(newTrack);
362+
if (play) return NextPlayable.OK_PLAY;
363+
else return NextPlayable.OK_PAUSE;
357364
}
358365

359-
@NotNull
360-
PlayableId getTrackAt(int index) {
361-
return playablesProvider.getTrackAt(index);
366+
@Nullable
367+
PlayableId nextPlayableDoNotSet() {
368+
int next = playablesProvider.getNextTrackIndex(true);
369+
if (next >= state.getTrackCount()) return null;
370+
else return playablesProvider.getTrackAt(next);
362371
}
363372

364373
@NotNull
365-
PlayableId getCurrentTrack() {
366-
return playablesProvider.getCurrentTrack();
374+
PreviousPlayable previousPlayable() {
375+
if (playablesProvider == null) return PreviousPlayable.MISSING_PROVIDER;
376+
state.setPlayingTrackIndex(playablesProvider.getPrevTrackIndex());
377+
return PreviousPlayable.OK;
378+
}
379+
380+
public enum PreviousPlayable {
381+
MISSING_PROVIDER, OK;
382+
383+
public boolean isOk() {
384+
return this == OK;
385+
}
386+
}
387+
388+
public enum NextPlayable {
389+
MISSING_PROVIDER, AUTOPLAY,
390+
OK_PLAY, OK_PAUSE;
391+
392+
public boolean isOk() {
393+
return this == OK_PLAY || this == OK_PAUSE;
394+
}
367395
}
368396

369397
private static class TrackSelector {

core/src/main/java/xyz/gianlu/librespot/player/contexts/SpotifyContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,5 +101,10 @@ class UnsupportedContextException extends Exception {
101101
UnsupportedContextException(@NotNull String message) {
102102
super(message);
103103
}
104+
105+
@NotNull
106+
public static UnsupportedContextException empty() {
107+
return new UnsupportedContextException("Empty context not supported!");
108+
}
104109
}
105110
}

0 commit comments

Comments
 (0)