diff --git a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java index a0086a58a..174ba8d9b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -560,7 +560,6 @@ public abstract class BasePlayer implements Player.EventListener, // Check timeline is up-to-date and has window if (playbackManager.expectedTimelineSize() != simpleExoPlayer.getCurrentTimeline().getWindowCount()) return; - if (simpleExoPlayer.getCurrentTimeline().getWindowCount() <= currentSourceIndex) return; // Check if window is ready Timeline.Window window = new Timeline.Window(); @@ -617,7 +616,7 @@ public abstract class BasePlayer implements Player.EventListener, public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { if (DEBUG) Log.d(TAG, "onPlayerStateChanged() called with: playWhenReady = [" + playWhenReady + "], playbackState = [" + playbackState + "]"); - if (getCurrentState() == STATE_PAUSED_SEEK || getCurrentState() == STATE_BLOCKED) { + if (getCurrentState() == STATE_PAUSED_SEEK) { if (DEBUG) Log.d(TAG, "onPlayerStateChanged() is currently blocked"); return; } @@ -639,8 +638,10 @@ public abstract class BasePlayer implements Player.EventListener, changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED); break; case Player.STATE_ENDED: // 4 - // Ensure the current window is loaded - if (simpleExoPlayer.isCurrentWindowSeekable()) { + // Ensure the current window has actually ended + // since single windows that are still loading may produce an ended state + if (simpleExoPlayer.isCurrentWindowSeekable() && + simpleExoPlayer.getCurrentPosition() >= simpleExoPlayer.getDuration()) { changeState(STATE_COMPLETED); isPrepared = false; } @@ -680,6 +681,7 @@ public abstract class BasePlayer implements Player.EventListener, if (simpleExoPlayer == null) return; if (DEBUG) Log.d(TAG, "Blocking..."); + simpleExoPlayer.removeListener(this); changeState(STATE_BLOCKED); wasPlaying = simpleExoPlayer.getPlayWhenReady(); @@ -703,6 +705,7 @@ public abstract class BasePlayer implements Player.EventListener, if (DEBUG) Log.d(TAG, "Unblocking..."); if (getCurrentState() == STATE_BLOCKED) changeState(STATE_BUFFERING); + simpleExoPlayer.addListener(this); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/player/playback/PlaybackManager.java b/app/src/main/java/org/schabi/newpipe/player/playback/PlaybackManager.java index 0ebb2ac7a..3bd2eb08f 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playback/PlaybackManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/playback/PlaybackManager.java @@ -125,7 +125,7 @@ public class PlaybackManager { break; } case UPDATE: - case SHUFFLE: + case REORDER: tryBlock(); resetSources(); break; diff --git a/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java b/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java index 6e53fcfca..7aac7fb1c 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java @@ -9,6 +9,7 @@ import org.schabi.newpipe.playlist.events.AppendEvent; import org.schabi.newpipe.playlist.events.InitEvent; import org.schabi.newpipe.playlist.events.PlayQueueMessage; import org.schabi.newpipe.playlist.events.RemoveEvent; +import org.schabi.newpipe.playlist.events.ReorderEvent; import org.schabi.newpipe.playlist.events.SelectEvent; import org.schabi.newpipe.playlist.events.UpdateEvent; @@ -29,7 +30,8 @@ public abstract class PlayQueue implements Serializable { public static final boolean DEBUG = true; - private final ArrayList streams; + private ArrayList backup; + private ArrayList streams; private final AtomicInteger queueIndex; private transient BehaviorSubject streamsEventBroadcast; @@ -165,6 +167,25 @@ public abstract class PlayQueue implements Serializable { broadcast(new RemoveEvent(index, isCurrent)); } + public synchronized void shuffle() { + backup = new ArrayList<>(streams); + final PlayQueueItem current = getCurrent(); + Collections.shuffle(streams); + queueIndex.set(streams.indexOf(current)); + + broadcast(new ReorderEvent(true)); + } + + public synchronized void unshuffle() { + if (backup == null) return; + final PlayQueueItem current = getCurrent(); + streams.clear(); + streams = backup; + queueIndex.set(streams.indexOf(current)); + + broadcast(new ReorderEvent(false)); + } + /*////////////////////////////////////////////////////////////////////////// // Rx Broadcast //////////////////////////////////////////////////////////////////////////*/ diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java index cdb0dfb27..eccf9bea7 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/events/PlayQueueEvent.java @@ -19,6 +19,6 @@ public enum PlayQueueEvent { UPDATE, // send when queue is shuffled - SHUFFLE + REORDER } diff --git a/app/src/main/java/org/schabi/newpipe/playlist/events/ReorderEvent.java b/app/src/main/java/org/schabi/newpipe/playlist/events/ReorderEvent.java new file mode 100644 index 000000000..e1f8826ec --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/playlist/events/ReorderEvent.java @@ -0,0 +1,18 @@ +package org.schabi.newpipe.playlist.events; + +public class ReorderEvent implements PlayQueueMessage { + final private boolean randomize; + + @Override + public PlayQueueEvent type() { + return PlayQueueEvent.REORDER; + } + + public ReorderEvent(final boolean randomize) { + this.randomize = randomize; + } + + public boolean isRandomize() { + return randomize; + } +}