Skip to content

Commit b21ede7

Browse files
committed
Player/handleIntent: Don’t delete queue when clicking on timestamp
Fixes #11013 We finally are at the point where we can have good logic around clicking on timestamps. This is pretty straightforward: 1) if we are already playing the stream (usual case), we skip to the correct second directly 2) If we don’t have a queue yet, create a trivial one with the stream 3) If we have a queue, we insert the video as next item and start playing it. The skipping logic in 1) is similar to the one further down in the old optimization block, but will always correctly fire for timestamps now. I copied it because it’s not quite the same code, and moving into a separate method at this stage would complicate the code too much.
1 parent a579cdb commit b21ede7

4 files changed

Lines changed: 79 additions & 14 deletions

File tree

app/src/main/java/org/schabi/newpipe/player/Player.java

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
import static org.schabi.newpipe.util.ListHelper.getResolutionIndex;
4747
import static java.util.concurrent.TimeUnit.MILLISECONDS;
4848

49-
import android.app.AlertDialog;
5049
import android.content.BroadcastReceiver;
5150
import android.content.Context;
5251
import android.content.Intent;
@@ -87,7 +86,6 @@
8786
import org.schabi.newpipe.R;
8887
import org.schabi.newpipe.databinding.PlayerBinding;
8988
import org.schabi.newpipe.error.ErrorInfo;
90-
import org.schabi.newpipe.error.ErrorPanelHelper;
9189
import org.schabi.newpipe.error.ErrorUtil;
9290
import org.schabi.newpipe.error.UserAction;
9391
import org.schabi.newpipe.extractor.Image;
@@ -125,9 +123,9 @@
125123
import org.schabi.newpipe.util.ListHelper;
126124
import org.schabi.newpipe.util.NavigationHelper;
127125
import org.schabi.newpipe.util.PermissionHelper;
128-
import org.schabi.newpipe.util.image.PicassoHelper;
129126
import org.schabi.newpipe.util.SerializedCache;
130127
import org.schabi.newpipe.util.StreamTypeUtil;
128+
import org.schabi.newpipe.util.image.PicassoHelper;
131129

132130
import java.util.List;
133131
import java.util.Optional;
@@ -407,9 +405,8 @@ public void handleIntent(@NonNull final Intent intent) {
407405
if (newQueue == null) {
408406
return;
409407
}
410-
final int currentIndex = playQueue.getIndex();
411-
playQueue.append(newQueue.getStreams());
412-
playQueue.move(playQueue.size() - 1, currentIndex + 1);
408+
final PlayQueueItem newItem = newQueue.getStreams().get(0);
409+
newQueue.enqueueNext(newItem, false);
413410
}
414411
return;
415412
}
@@ -421,9 +418,43 @@ public void handleIntent(@NonNull final Intent intent) {
421418
streamItemDisposable.add(single.subscribeOn(Schedulers.io())
422419
.observeOn(AndroidSchedulers.mainThread())
423420
.subscribe(info -> {
424-
final PlayQueue newPlayQueue = new SinglePlayQueue(info,
425-
dat.getSeconds() * 1000L);
426-
NavigationHelper.playOnPopupPlayer(context, playQueue, false);
421+
final @Nullable PlayQueue oldPlayQueue = playQueue;
422+
info.setStartPosition(dat.getSeconds());
423+
final PlayQueueItem playQueueItem = new PlayQueueItem(info);
424+
425+
// If the stream is already playing,
426+
// we can just seek to the appropriate timestamp
427+
if (oldPlayQueue != null
428+
&& playQueueItem.isSameItem(oldPlayQueue.getItem())) {
429+
// Player can have state = IDLE when playback is stopped or failed
430+
// and we should retry in this case
431+
if (simpleExoPlayer.getPlaybackState()
432+
== com.google.android.exoplayer2.Player.STATE_IDLE) {
433+
simpleExoPlayer.prepare();
434+
}
435+
simpleExoPlayer.seekTo(oldPlayQueue.getIndex(),
436+
dat.getSeconds() * 1000L);
437+
simpleExoPlayer.setPlayWhenReady(playWhenReady);
438+
439+
} else {
440+
final PlayQueue newPlayQueue;
441+
442+
// If there is no queue yet, just add our item
443+
if (oldPlayQueue == null) {
444+
newPlayQueue = new SinglePlayQueue(playQueueItem);
445+
446+
// else we add the timestamped stream behind the current video
447+
// and start playing it.
448+
} else {
449+
oldPlayQueue.enqueueNext(playQueueItem, true);
450+
oldPlayQueue.offsetIndex(1);
451+
newPlayQueue = oldPlayQueue;
452+
}
453+
initPlayback(newPlayQueue, playWhenReady);
454+
}
455+
456+
handleIntentPost(oldPlayerType);
457+
427458
}, throwable -> {
428459
final var errorInfo = new ErrorInfo(throwable, UserAction.PLAY_ON_POPUP,
429460
dat.getUrl());
@@ -460,7 +491,7 @@ public void handleIntent(@NonNull final Intent intent) {
460491
if (!exoPlayerIsNull()
461492
&& newQueue.size() == 1 && newQueue.getItem() != null
462493
&& playQueue != null && playQueue.size() == 1 && playQueue.getItem() != null
463-
&& newQueue.getItem().getUrl().equals(playQueue.getItem().getUrl())
494+
&& newQueue.getItem().isSameItem(playQueue.getItem())
464495
&& newQueue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET) {
465496
// Player can have state = IDLE when playback is stopped or failed
466497
// and we should retry in this case
@@ -526,6 +557,7 @@ public void handleIntent(@NonNull final Intent intent) {
526557
handleIntentPost(oldPlayerType);
527558
}
528559

560+
529561
private void handleIntentPost(final PlayerType oldPlayerType) {
530562
if (oldPlayerType != playerType && playQueue != null) {
531563
// If playerType changes from one to another we should reload the player

app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueue.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,22 @@ public synchronized void append(@NonNull final List<PlayQueueItem> items) {
291291
broadcast(new AppendEvent(itemList.size()));
292292
}
293293

294+
/**
295+
* Add the given item after the current stream.
296+
*
297+
* @param item item to add.
298+
* @param skipIfSame if set, skip adding if the next stream is the same stream.
299+
*/
300+
public void enqueueNext(@NonNull final PlayQueueItem item, final boolean skipIfSame) {
301+
final int currentIndex = getIndex();
302+
// if the next item is the same item as the one we want to enqueue, skip if flag is true
303+
if (skipIfSame && item.isSameItem(getItem(currentIndex + 1))) {
304+
return;
305+
}
306+
append(List.of(item));
307+
move(size() - 1, currentIndex + 1);
308+
}
309+
294310
/**
295311
* Removes the item at the given index from the play queue.
296312
* <p>
@@ -529,8 +545,7 @@ public boolean equalStreams(@Nullable final PlayQueue other) {
529545
final PlayQueueItem stream = streams.get(i);
530546
final PlayQueueItem otherStream = other.streams.get(i);
531547
// Check is based on serviceId and URL
532-
if (stream.getServiceId() != otherStream.getServiceId()
533-
|| !stream.getUrl().equals(otherStream.getUrl())) {
548+
if (!stream.isSameItem(otherStream)) {
534549
return false;
535550
}
536551
}

app/src/main/java/org/schabi/newpipe/player/playqueue/PlayQueueItem.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class PlayQueueItem implements Serializable {
3838
private long recoveryPosition;
3939
private Throwable error;
4040

41-
PlayQueueItem(@NonNull final StreamInfo info) {
41+
public PlayQueueItem(@NonNull final StreamInfo info) {
4242
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
4343
info.getThumbnails(), info.getUploaderName(),
4444
info.getUploaderUrl(), info.getStreamType());
@@ -71,6 +71,22 @@ private PlayQueueItem(@Nullable final String name, @Nullable final String url,
7171
this.recoveryPosition = RECOVERY_UNSET;
7272
}
7373

74+
/** Whether these two items should be treated as the same stream
75+
* for the sake of keeping the same player running when e.g. jumping between timestamps.
76+
*
77+
* @param other the {@link PlayQueueItem} to compare against.
78+
* @return whether the two items are the same so the stream can be re-used.
79+
*/
80+
public boolean isSameItem(@Nullable final PlayQueueItem other) {
81+
if (other == null) {
82+
return false;
83+
}
84+
// We assume that the same service & URL uniquely determines
85+
// that we can keep the same stream running.
86+
return getServiceId() == other.getServiceId()
87+
&& getUrl().equals(other.getUrl());
88+
}
89+
7490
@NonNull
7591
public String getTitle() {
7692
return title;

app/src/main/java/org/schabi/newpipe/player/playqueue/SinglePlayQueue.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ public SinglePlayQueue(final StreamInfoItem item) {
1616
public SinglePlayQueue(final StreamInfo info) {
1717
super(0, List.of(new PlayQueueItem(info)));
1818
}
19-
19+
public SinglePlayQueue(final PlayQueueItem item) {
20+
super(0, List.of(item));
21+
}
2022
public SinglePlayQueue(final StreamInfo info, final long startPosition) {
2123
super(0, List.of(new PlayQueueItem(info)));
2224
getItem().setRecoveryPosition(startPosition);

0 commit comments

Comments
 (0)