mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-11 09:50:32 +00:00
-Functional playlist using full play queue buffering.
This commit is contained in:
parent
183181ee54
commit
5c01f04a07
@ -560,46 +560,61 @@ public abstract class BasePlayer implements Player.EventListener,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void block() {
|
public void block() {
|
||||||
if (currentState != STATE_LOADING) return;
|
Log.d(TAG, "Blocking...");
|
||||||
|
|
||||||
changeState(STATE_LOADING);
|
if (currentState != STATE_PLAYING) return;
|
||||||
simpleExoPlayer.setPlayWhenReady(false);
|
|
||||||
|
simpleExoPlayer.stop();
|
||||||
windowIndex = simpleExoPlayer.getCurrentWindowIndex();
|
windowIndex = simpleExoPlayer.getCurrentWindowIndex();
|
||||||
windowPos = Math.max(0, simpleExoPlayer.getContentPosition());
|
windowPos = Math.max(0, simpleExoPlayer.getContentPosition());
|
||||||
|
|
||||||
|
changeState(STATE_BUFFERING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unblock() {
|
public void unblock() {
|
||||||
if (currentState == STATE_PLAYING) return;
|
Log.d(TAG, "Unblocking...");
|
||||||
|
|
||||||
if (playbackManager.getMediaSource().getSize() > 0) {
|
if (currentState != STATE_BUFFERING) return;
|
||||||
simpleExoPlayer.seekToDefaultPosition();
|
|
||||||
//simpleExoPlayer.seekTo(windowIndex, windowPos);
|
if (windowIndex != playbackManager.getCurrentSourceIndex()) {
|
||||||
simpleExoPlayer.setPlayWhenReady(true);
|
windowIndex = playbackManager.getCurrentSourceIndex();
|
||||||
changeState(STATE_PLAYING);
|
windowPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simpleExoPlayer.prepare(playbackManager.getMediaSource());
|
||||||
|
simpleExoPlayer.seekTo(windowIndex, windowPos);
|
||||||
|
simpleExoPlayer.setPlayWhenReady(true);
|
||||||
|
changeState(STATE_PLAYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sync(final int windowIndex, final long windowPos, final StreamInfo info) {
|
public void sync(final int windowIndex, final long windowPos, final StreamInfo info) {
|
||||||
|
Log.d(TAG, "Syncing...");
|
||||||
|
|
||||||
videoUrl = info.webpage_url;
|
videoUrl = info.webpage_url;
|
||||||
videoThumbnailUrl = info.thumbnail_url;
|
videoThumbnailUrl = info.thumbnail_url;
|
||||||
videoTitle = info.title;
|
videoTitle = info.title;
|
||||||
channelName = info.uploader;
|
channelName = info.uploader;
|
||||||
|
|
||||||
if (simpleExoPlayer.getCurrentWindowIndex() != windowIndex) {
|
if (simpleExoPlayer.getCurrentWindowIndex() != windowIndex) {
|
||||||
|
Log.e(TAG, "Rewinding to correct window");
|
||||||
simpleExoPlayer.seekTo(windowIndex, windowPos);
|
simpleExoPlayer.seekTo(windowIndex, windowPos);
|
||||||
} else {
|
} else {
|
||||||
|
Log.d(TAG, "Correct window");
|
||||||
simpleExoPlayer.seekTo(windowPos);
|
simpleExoPlayer.seekTo(windowPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
|
Log.d(TAG, "Initializing...");
|
||||||
|
|
||||||
if (simpleExoPlayer.getPlaybackState() != Player.STATE_IDLE) simpleExoPlayer.stop();
|
if (simpleExoPlayer.getPlaybackState() != Player.STATE_IDLE) simpleExoPlayer.stop();
|
||||||
simpleExoPlayer.prepare(playbackManager.getMediaSource());
|
simpleExoPlayer.prepare(playbackManager.getMediaSource());
|
||||||
simpleExoPlayer.setPlayWhenReady(false);
|
simpleExoPlayer.seekToDefaultPosition();
|
||||||
changeState(STATE_BUFFERING);
|
simpleExoPlayer.setPlayWhenReady(true);
|
||||||
|
changeState(STATE_PLAYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,6 +27,8 @@ import io.reactivex.functions.Consumer;
|
|||||||
|
|
||||||
class MediaSourceManager {
|
class MediaSourceManager {
|
||||||
private final String TAG = "MediaSourceManager@" + Integer.toHexString(hashCode());
|
private final String TAG = "MediaSourceManager@" + Integer.toHexString(hashCode());
|
||||||
|
// One-side rolling window size for default loading
|
||||||
|
// Effectively loads WINDOW_SIZE * 2 streams
|
||||||
private static final int WINDOW_SIZE = 3;
|
private static final int WINDOW_SIZE = 3;
|
||||||
|
|
||||||
private final DynamicConcatenatingMediaSource sources;
|
private final DynamicConcatenatingMediaSource sources;
|
||||||
@ -42,13 +44,40 @@ class MediaSourceManager {
|
|||||||
private Subscription loadingReactor;
|
private Subscription loadingReactor;
|
||||||
private CompositeDisposable disposables;
|
private CompositeDisposable disposables;
|
||||||
|
|
||||||
|
private boolean isBlocked;
|
||||||
|
|
||||||
interface PlaybackListener {
|
interface PlaybackListener {
|
||||||
|
/*
|
||||||
|
* Called when the initial video has been loaded.
|
||||||
|
* Signals to the listener that the media source is prepared, and
|
||||||
|
* the player is ready to go.
|
||||||
|
* */
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the stream at the current queue index is not ready yet.
|
||||||
|
* Signals to the listener to block the player from playing anything.
|
||||||
|
* */
|
||||||
void block();
|
void block();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the stream at the current queue index is ready.
|
||||||
|
* Signals to the listener to resume the player.
|
||||||
|
* May be called at any time, even when the player is unblocked.
|
||||||
|
* */
|
||||||
void unblock();
|
void unblock();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the queue index is refreshed.
|
||||||
|
* Signals to the listener to synchronize the player's window to the manager's
|
||||||
|
* window.
|
||||||
|
* */
|
||||||
void sync(final int windowIndex, final long windowPos, final StreamInfo info);
|
void sync(final int windowIndex, final long windowPos, final StreamInfo info);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Requests the listener to resolve a stream info into a media source respective
|
||||||
|
* of the listener's implementation (background, popup or main video player),
|
||||||
|
* */
|
||||||
MediaSource sourceOf(final StreamInfo info);
|
MediaSource sourceOf(final StreamInfo info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +96,13 @@ class MediaSourceManager {
|
|||||||
.subscribe(getReactor());
|
.subscribe(getReactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Exposed Methods
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the media source index of the currently playing stream.
|
||||||
|
* */
|
||||||
int getCurrentSourceIndex() {
|
int getCurrentSourceIndex() {
|
||||||
return sourceToQueueIndex.indexOf(playQueue.getIndex());
|
return sourceToQueueIndex.indexOf(playQueue.getIndex());
|
||||||
}
|
}
|
||||||
@ -76,6 +112,11 @@ class MediaSourceManager {
|
|||||||
return sources;
|
return sources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when the player has seamlessly transitioned to another stream.
|
||||||
|
* Currently only expecting transitioning to the next stream and updates
|
||||||
|
* the play queue that a transition has occurred.
|
||||||
|
* */
|
||||||
void refresh(final int newSourceIndex) {
|
void refresh(final int newSourceIndex) {
|
||||||
if (newSourceIndex == getCurrentSourceIndex()) return;
|
if (newSourceIndex == getCurrentSourceIndex()) return;
|
||||||
|
|
||||||
@ -89,15 +130,107 @@ class MediaSourceManager {
|
|||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void select() {
|
void dispose() {
|
||||||
if (getCurrentSourceIndex() != -1) {
|
if (loadingReactor != null) loadingReactor.cancel();
|
||||||
sync();
|
if (playQueueReactor != null) playQueueReactor.cancel();
|
||||||
} else {
|
if (disposables != null) disposables.dispose();
|
||||||
playbackListener.block();
|
|
||||||
load();
|
loadingReactor = null;
|
||||||
|
playQueueReactor = null;
|
||||||
|
disposables = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Event Reactor
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private Subscriber<PlayQueueMessage> getReactor() {
|
||||||
|
return new Subscriber<PlayQueueMessage>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(@NonNull Subscription d) {
|
||||||
|
if (playQueueReactor != null) playQueueReactor.cancel();
|
||||||
|
playQueueReactor = d;
|
||||||
|
playQueueReactor.request(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(@NonNull PlayQueueMessage event) {
|
||||||
|
// why no pattern matching in Java =(
|
||||||
|
switch (event.type()) {
|
||||||
|
case INIT:
|
||||||
|
init();
|
||||||
|
break;
|
||||||
|
case APPEND:
|
||||||
|
load();
|
||||||
|
break;
|
||||||
|
case SELECT:
|
||||||
|
onSelect();
|
||||||
|
break;
|
||||||
|
case REMOVE:
|
||||||
|
final RemoveEvent removeEvent = (RemoveEvent) event;
|
||||||
|
remove(removeEvent.index());
|
||||||
|
break;
|
||||||
|
case SWAP:
|
||||||
|
final SwapEvent swapEvent = (SwapEvent) event;
|
||||||
|
swap(swapEvent.getFrom(), swapEvent.getTo());
|
||||||
|
break;
|
||||||
|
case NEXT:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPlayQueueReady() && !isBlocked) {
|
||||||
|
playbackListener.block();
|
||||||
|
playQueue.fetch();
|
||||||
|
}
|
||||||
|
if (playQueueReactor != null) playQueueReactor.request(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NonNull Throwable e) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Internal Helpers
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private boolean isPlayQueueReady() {
|
||||||
|
return playQueue.isComplete() || playQueue.size() - playQueue.getIndex() > WINDOW_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCurrentIndexLoaded() {
|
||||||
|
return getCurrentSourceIndex() != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryUnblock() {
|
||||||
|
if (isPlayQueueReady() && isCurrentIndexLoaded() && isBlocked) {
|
||||||
|
isBlocked = false;
|
||||||
|
playbackListener.unblock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Responds to a SELECT event.
|
||||||
|
* When a change occur, the manager prepares by loading more.
|
||||||
|
* If the current item has not been fully loaded,
|
||||||
|
* */
|
||||||
|
private void onSelect() {
|
||||||
|
if (isCurrentIndexLoaded()) {
|
||||||
|
sync();
|
||||||
|
} else if (!isBlocked) {
|
||||||
|
playbackListener.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
private void sync() {
|
private void sync() {
|
||||||
final Consumer<StreamInfo> onSuccess = new Consumer<StreamInfo>() {
|
final Consumer<StreamInfo> onSuccess = new Consumer<StreamInfo>() {
|
||||||
@Override
|
@Override
|
||||||
@ -121,6 +254,47 @@ class MediaSourceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
final PlayQueueItem init = playQueue.getCurrent();
|
||||||
|
|
||||||
|
init.getStream().subscribe(new MaybeObserver<StreamInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(@NonNull Disposable d) {
|
||||||
|
if (disposables != null) {
|
||||||
|
disposables.add(d);
|
||||||
|
} else {
|
||||||
|
d.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(@NonNull StreamInfo streamInfo) {
|
||||||
|
final MediaSource source = playbackListener.sourceOf(streamInfo);
|
||||||
|
insert(playQueue.indexOf(init), source);
|
||||||
|
|
||||||
|
if (getCurrentSourceIndex() != -1) {
|
||||||
|
playbackListener.init();
|
||||||
|
sync();
|
||||||
|
load();
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(@NonNull Throwable e) {
|
||||||
|
playQueue.remove(playQueue.indexOf(init));
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
|
playQueue.remove(playQueue.indexOf(init));
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void load(final PlayQueueItem item) {
|
private void load(final PlayQueueItem item) {
|
||||||
item.getStream().subscribe(new MaybeObserver<StreamInfo>() {
|
item.getStream().subscribe(new MaybeObserver<StreamInfo>() {
|
||||||
@Override
|
@Override
|
||||||
@ -136,21 +310,38 @@ class MediaSourceManager {
|
|||||||
public void onSuccess(@NonNull StreamInfo streamInfo) {
|
public void onSuccess(@NonNull StreamInfo streamInfo) {
|
||||||
final MediaSource source = playbackListener.sourceOf(streamInfo);
|
final MediaSource source = playbackListener.sourceOf(streamInfo);
|
||||||
insert(playQueue.indexOf(item), source);
|
insert(playQueue.indexOf(item), source);
|
||||||
if (getCurrentSourceIndex() != -1) playbackListener.unblock();
|
tryUnblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(@NonNull Throwable e) {
|
public void onError(@NonNull Throwable e) {
|
||||||
playQueue.remove(playQueue.indexOf(item));
|
playQueue.remove(playQueue.indexOf(item));
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
playQueue.remove(playQueue.indexOf(item));
|
playQueue.remove(playQueue.indexOf(item));
|
||||||
|
load();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Media Source List Manipulation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public void replace(final int queueIndex, final MediaSource source) {
|
||||||
|
if (queueIndex < 0) return;
|
||||||
|
|
||||||
|
final int sourceIndex = sourceToQueueIndex.indexOf(queueIndex);
|
||||||
|
if (sourceIndex != -1) {
|
||||||
|
// Add the source after the one to remove, so the window will remain the same in the player
|
||||||
|
sources.addMediaSource(sourceIndex + 1, source);
|
||||||
|
sources.removeMediaSource(sourceIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Insert source into playlist with position in respect to the play queue
|
// Insert source into playlist with position in respect to the play queue
|
||||||
// If the play queue index already exists, then the insert is ignored
|
// If the play queue index already exists, then the insert is ignored
|
||||||
private void insert(final int queueIndex, final MediaSource source) {
|
private void insert(final int queueIndex, final MediaSource source) {
|
||||||
@ -178,17 +369,6 @@ class MediaSourceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void replace(final int queueIndex, final MediaSource source) {
|
|
||||||
if (queueIndex < 0) return;
|
|
||||||
|
|
||||||
final int sourceIndex = sourceToQueueIndex.indexOf(queueIndex);
|
|
||||||
if (sourceIndex != -1) {
|
|
||||||
// Add the source after the one to remove, so the window will remain the same in the player
|
|
||||||
sources.addMediaSource(sourceIndex + 1, source);
|
|
||||||
sources.removeMediaSource(sourceIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void swap(final int source, final int target) {
|
private void swap(final int source, final int target) {
|
||||||
final int sourceIndex = sourceToQueueIndex.indexOf(source);
|
final int sourceIndex = sourceToQueueIndex.indexOf(source);
|
||||||
final int targetIndex = sourceToQueueIndex.indexOf(target);
|
final int targetIndex = sourceToQueueIndex.indexOf(target);
|
||||||
@ -201,69 +381,4 @@ class MediaSourceManager {
|
|||||||
remove(targetIndex);
|
remove(targetIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Subscriber<PlayQueueMessage> getReactor() {
|
|
||||||
return new Subscriber<PlayQueueMessage>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(@NonNull Subscription d) {
|
|
||||||
if (playQueueReactor != null) playQueueReactor.cancel();
|
|
||||||
playQueueReactor = d;
|
|
||||||
playQueueReactor.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(@NonNull PlayQueueMessage event) {
|
|
||||||
if (playQueue.size() - playQueue.getIndex() < WINDOW_SIZE && !playQueue.isComplete()) {
|
|
||||||
playbackListener.block();
|
|
||||||
playQueue.fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
// why no pattern matching in Java =(
|
|
||||||
switch (event.type()) {
|
|
||||||
case INIT:
|
|
||||||
playbackListener.init();
|
|
||||||
case APPEND:
|
|
||||||
load();
|
|
||||||
break;
|
|
||||||
case SELECT:
|
|
||||||
select();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REMOVE:
|
|
||||||
final RemoveEvent removeEvent = (RemoveEvent) event;
|
|
||||||
remove(removeEvent.index());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SWAP:
|
|
||||||
final SwapEvent swapEvent = (SwapEvent) event;
|
|
||||||
swap(swapEvent.getFrom(), swapEvent.getTo());
|
|
||||||
break;
|
|
||||||
case NEXT:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playQueueReactor != null) playQueueReactor.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(@NonNull Throwable e) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispose() {
|
|
||||||
if (loadingReactor != null) loadingReactor.cancel();
|
|
||||||
if (playQueueReactor != null) playQueueReactor.cancel();
|
|
||||||
if (disposables != null) disposables.dispose();
|
|
||||||
|
|
||||||
loadingReactor = null;
|
|
||||||
playQueueReactor = null;
|
|
||||||
disposables = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -201,26 +201,27 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
|||||||
simpleExoPlayer.setVideoListener(this);
|
simpleExoPlayer.setVideoListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @SuppressWarnings("unchecked")
|
||||||
|
// public void handleIntent2(Intent intent) {
|
||||||
|
// super.handleIntent(intent);
|
||||||
|
// if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
|
||||||
|
// if (intent == null) return;
|
||||||
|
//
|
||||||
|
// selectedIndexStream = intent.getIntExtra(INDEX_SEL_VIDEO_STREAM, -1);
|
||||||
|
//
|
||||||
|
// Serializable serializable = intent.getSerializableExtra(VIDEO_STREAMS_LIST);
|
||||||
|
//
|
||||||
|
// if (serializable instanceof ArrayList) videoStreamsList = (ArrayList<VideoStream>) serializable;
|
||||||
|
// if (serializable instanceof Vector) videoStreamsList = new ArrayList<>((List<VideoStream>) serializable);
|
||||||
|
//
|
||||||
|
// Serializable audioStream = intent.getSerializableExtra(VIDEO_ONLY_AUDIO_STREAM);
|
||||||
|
// if (audioStream != null) videoOnlyAudioStream = (AudioStream) audioStream;
|
||||||
|
//
|
||||||
|
// startedFromNewPipe = intent.getBooleanExtra(STARTED_FROM_NEWPIPE, true);
|
||||||
|
// play(true);
|
||||||
|
// }
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void handleIntent2(Intent intent) {
|
|
||||||
super.handleIntent(intent);
|
|
||||||
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
|
|
||||||
if (intent == null) return;
|
|
||||||
|
|
||||||
selectedIndexStream = intent.getIntExtra(INDEX_SEL_VIDEO_STREAM, -1);
|
|
||||||
|
|
||||||
Serializable serializable = intent.getSerializableExtra(VIDEO_STREAMS_LIST);
|
|
||||||
|
|
||||||
if (serializable instanceof ArrayList) videoStreamsList = (ArrayList<VideoStream>) serializable;
|
|
||||||
if (serializable instanceof Vector) videoStreamsList = new ArrayList<>((List<VideoStream>) serializable);
|
|
||||||
|
|
||||||
Serializable audioStream = intent.getSerializableExtra(VIDEO_ONLY_AUDIO_STREAM);
|
|
||||||
if (audioStream != null) videoOnlyAudioStream = (AudioStream) audioStream;
|
|
||||||
|
|
||||||
startedFromNewPipe = intent.getBooleanExtra(STARTED_FROM_NEWPIPE, true);
|
|
||||||
play(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleIntent(Intent intent) {
|
public void handleIntent(Intent intent) {
|
||||||
if (intent == null) return;
|
if (intent == null) return;
|
||||||
|
|
||||||
@ -454,6 +455,9 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer.
|
|||||||
public void onUpdateProgress(int currentProgress, int duration, int bufferPercent) {
|
public void onUpdateProgress(int currentProgress, int duration, int bufferPercent) {
|
||||||
if (!isPrepared) return;
|
if (!isPrepared) return;
|
||||||
|
|
||||||
|
if (duration != playbackSeekBar.getMax()) {
|
||||||
|
playbackEndTime.setText(getTimeString(duration));
|
||||||
|
}
|
||||||
if (currentState != STATE_PAUSED) {
|
if (currentState != STATE_PAUSED) {
|
||||||
if (currentState != STATE_PAUSED_SEEK) playbackSeekBar.setProgress(currentProgress);
|
if (currentState != STATE_PAUSED_SEEK) playbackSeekBar.setProgress(currentProgress);
|
||||||
playbackCurrentTime.setText(getTimeString(currentProgress));
|
playbackCurrentTime.setText(getTimeString(currentProgress));
|
||||||
|
@ -32,12 +32,15 @@ public class ExternalPlayQueue extends PlayQueue {
|
|||||||
|
|
||||||
public ExternalPlayQueue(final String playlistUrl,
|
public ExternalPlayQueue(final String playlistUrl,
|
||||||
final PlayListInfo info,
|
final PlayListInfo info,
|
||||||
final int nextPage,
|
final int currentPage,
|
||||||
final int index) {
|
final int index) {
|
||||||
super(index, extractPlaylistItems(info));
|
super(index, extractPlaylistItems(info));
|
||||||
|
|
||||||
this.service = getService(info.service_id);
|
this.service = getService(info.service_id);
|
||||||
this.pageNumber = new AtomicInteger(nextPage);
|
|
||||||
|
this.isComplete = !info.hasNextPage;
|
||||||
|
this.pageNumber = new AtomicInteger(currentPage + 1);
|
||||||
|
|
||||||
this.playlistUrl = playlistUrl;
|
this.playlistUrl = playlistUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +57,7 @@ public class ExternalPlayQueue extends PlayQueue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fetch() {
|
public void fetch() {
|
||||||
|
if (isComplete) return;
|
||||||
if (fetchReactor != null && !fetchReactor.isDisposed()) return;
|
if (fetchReactor != null && !fetchReactor.isDisposed()) return;
|
||||||
|
|
||||||
final Callable<PlayListInfo> task = new Callable<PlayListInfo>() {
|
final Callable<PlayListInfo> task = new Callable<PlayListInfo>() {
|
||||||
@ -77,7 +81,6 @@ public class ExternalPlayQueue extends PlayQueue {
|
|||||||
fetchReactor = Maybe.fromCallable(task)
|
fetchReactor = Maybe.fromCallable(task)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.onErrorComplete()
|
|
||||||
.subscribe(onSuccess);
|
.subscribe(onSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public abstract class PlayQueue {
|
|||||||
streams = Collections.synchronizedList(new ArrayList<PlayQueueItem>());
|
streams = Collections.synchronizedList(new ArrayList<PlayQueueItem>());
|
||||||
streams.addAll(startWith);
|
streams.addAll(startWith);
|
||||||
|
|
||||||
queueIndex = new AtomicInteger(index);
|
queueIndex = new AtomicInteger(97);
|
||||||
|
|
||||||
eventBroadcast = BehaviorSubject.create();
|
eventBroadcast = BehaviorSubject.create();
|
||||||
broadcastReceiver = eventBroadcast
|
broadcastReceiver = eventBroadcast
|
||||||
@ -62,8 +62,6 @@ public abstract class PlayQueue {
|
|||||||
// load partial queue in the background, does nothing if the queue is complete
|
// load partial queue in the background, does nothing if the queue is complete
|
||||||
public abstract void fetch();
|
public abstract void fetch();
|
||||||
|
|
||||||
// returns a Rx Future to the stream info of the play queue item at index
|
|
||||||
// may return an empty of the queue is incomplete
|
|
||||||
public abstract PlayQueueItem get(int index);
|
public abstract PlayQueueItem get(int index);
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
@ -103,6 +103,7 @@ public class PlayQueueItem {
|
|||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnError(onError)
|
.doOnError(onError)
|
||||||
.doOnComplete(onComplete)
|
.doOnComplete(onComplete)
|
||||||
|
.retry(3)
|
||||||
.cache();
|
.cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user