From b54d18d8889c2092e49896fc064ae2e2bddf4479 Mon Sep 17 00:00:00 2001 From: John Zhen M Date: Tue, 5 Sep 2017 12:27:12 -0700 Subject: [PATCH] -Changed intents to start all players, including player swap. -Make play queue and items serializable -Removed now deprecated code for playing url in exoplayer --- .../list/playlist/PlaylistFragment.java | 19 +-- .../newpipe/player/BackgroundPlayer.java | 29 ++-- .../org/schabi/newpipe/player/BasePlayer.java | 140 ++++++++++++------ .../newpipe/player/MainVideoPlayer.java | 24 +-- .../newpipe/player/MediaSourceManager.java | 41 +++-- .../newpipe/player/PopupVideoPlayer.java | 40 ++--- .../schabi/newpipe/player/VideoPlayer.java | 120 +++++++-------- .../newpipe/playlist/ExternalPlayQueue.java | 17 +-- .../schabi/newpipe/playlist/PlayQueue.java | 74 ++++----- .../newpipe/playlist/PlayQueueItem.java | 35 ++++- .../newpipe/playlist/SinglePlayQueue.java | 21 +++ .../schabi/newpipe/util/NavigationHelper.java | 69 +++++---- 12 files changed, 368 insertions(+), 261 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 97779eadc..20d1eadeb 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -20,15 +20,12 @@ import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.playlist.PlaylistInfo; -import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.fragments.list.BaseListInfoFragment; import org.schabi.newpipe.player.MainVideoPlayer; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.NavigationHelper; -import java.util.List; - import io.reactivex.Single; import static org.schabi.newpipe.util.AnimationUtils.animateView; @@ -141,7 +138,7 @@ public class PlaylistFragment extends BaseListInfoFragment { } imageLoader.displayImage(result.uploader_avatar_url, headerUploaderAvatar, DISPLAY_AVATAR_OPTIONS); - headerStreamCount.setText(result.stream_count + " videos"); + headerStreamCount.setText(getResources().getQuantityString(R.plurals.videos, (int) result.stream_count)); if (!result.errors.isEmpty()) { showSnackBarError(result.errors, UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(result.service_id), result.url, 0); @@ -150,19 +147,15 @@ public class PlaylistFragment extends BaseListInfoFragment { headerPlayAllButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - play(); + final Intent intent = NavigationHelper.getExternalPlaylistIntent( + activity, MainVideoPlayer.class, currentInfo, infoListAdapter.getItemsList(), 0 + ); + + startActivity(intent); } }); } - private void play() { - Intent mIntent = new Intent(activity, MainVideoPlayer.class) - .putExtra("serviceId", serviceId) - .putExtra("index", 0) - .putExtra("streams", infoListAdapter.getItemsList()) - .putExtra("nextPageUrl", currentInfo.next_streams_url); - startActivity(mIntent); - } @Override public void handleNextItems(ListExtractor.NextItemsResult result) { diff --git a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java index b3c1fd037..4bf8b1421 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -268,9 +268,9 @@ public class BackgroundPlayer extends Service { @Override public void handleIntent(Intent intent) { super.handleIntent(intent); - Serializable serializable = intent.getSerializableExtra(BackgroundPlayer.AUDIO_STREAM); - if (serializable instanceof AudioStream) audioStream = (AudioStream) serializable; - playUrl(audioStream.url, MediaFormat.getSuffixById(audioStream.format), true); + + notBuilder = createNotification(); + startForeground(NOTIFICATION_ID, notBuilder.build()); if (bigNotRemoteView != null) bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false); if (notRemoteView != null) notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 0, false); @@ -294,14 +294,6 @@ public class BackgroundPlayer extends Service { } } - @Override - public void playUrl(String url, String format, boolean autoPlay) { - super.playUrl(url, format, autoPlay); - - notBuilder = createNotification(); - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - @Override public void onPrepared(boolean playWhenReady) { super.onPrepared(playWhenReady); @@ -348,15 +340,13 @@ public class BackgroundPlayer extends Service { @Override public void onFastRewind() { -// super.onFastRewind(); - simpleExoPlayer.seekTo(0, 0); + playQueue.setIndex(playQueue.getIndex() - 1); triggerProgressUpdate(); } @Override public void onFastForward() { -// super.onFastForward(); - simpleExoPlayer.seekTo(2, 0); + playQueue.setIndex(playQueue.getIndex() + 1); triggerProgressUpdate(); } @@ -380,6 +370,15 @@ public class BackgroundPlayer extends Service { @Override public void onError(Exception exception) { exception.printStackTrace(); + } + + /*////////////////////////////////////////////////////////////////////////// + // Playback Listener + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void shutdown() { + super.shutdown(); stopSelf(); } 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 48a9a7b99..90e206c84 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -70,13 +70,21 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene import org.schabi.newpipe.Downloader; import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.stream.StreamInfo; +import org.schabi.newpipe.extractor.stream.StreamInfoItem; +import org.schabi.newpipe.playlist.ExternalPlayQueue; import org.schabi.newpipe.playlist.PlayQueue; +import org.schabi.newpipe.playlist.PlayQueueItem; +import org.schabi.newpipe.playlist.SinglePlayQueue; import java.io.File; +import java.io.Serializable; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.Formatter; +import java.util.List; import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; @@ -90,7 +98,7 @@ public abstract class BasePlayer implements Player.EventListener, AudioManager.OnAudioFocusChangeListener, MediaSourceManager.PlaybackListener { // TODO: Check api version for deprecated audio manager methods - public static final boolean DEBUG = false; + public static final boolean DEBUG = true; public static final String TAG = "BasePlayer"; protected Context context; @@ -104,6 +112,11 @@ public abstract class BasePlayer implements Player.EventListener, // Intent //////////////////////////////////////////////////////////////////////////*/ + public static final String INTENT_TYPE = "intent_type"; + public static final String SINGLE_STREAM = "single"; + public static final String EXTERNAL_PLAYLIST = "external"; + public static final String INTERNAL_PLAYLIST = "internal"; + public static final String VIDEO_URL = "video_url"; public static final String VIDEO_TITLE = "video_title"; public static final String VIDEO_THUMBNAIL_URL = "video_thumbnail_url"; @@ -111,6 +124,9 @@ public abstract class BasePlayer implements Player.EventListener, public static final String CHANNEL_NAME = "channel_name"; public static final String PLAYBACK_SPEED = "playback_speed"; + public static final String RESTORE_QUEUE_INDEX = "restore_queue_index"; + public static final String RESTORE_WINDOW_POS = "restore_window_pos"; + protected Bitmap videoThumbnail = null; protected String videoUrl = ""; protected String videoTitle = ""; @@ -125,8 +141,8 @@ public abstract class BasePlayer implements Player.EventListener, protected MediaSourceManager playbackManager; protected PlayQueue playQueue; - private int windowIndex; - private long windowPos; + protected int restoreQueueIndex; + protected long restoreWindowPos; /*////////////////////////////////////////////////////////////////////////// // Player @@ -219,15 +235,54 @@ public abstract class BasePlayer implements Player.EventListener, if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]"); if (intent == null) return; - videoUrl = intent.getStringExtra(VIDEO_URL); - videoTitle = intent.getStringExtra(VIDEO_TITLE); - videoThumbnailUrl = intent.getStringExtra(VIDEO_THUMBNAIL_URL); - videoStartPos = intent.getLongExtra(START_POSITION, -1L); - uploaderName = intent.getStringExtra(CHANNEL_NAME); + restoreQueueIndex = intent.getIntExtra(RESTORE_QUEUE_INDEX, 0); + restoreWindowPos = intent.getLongExtra(START_POSITION, 0); setPlaybackSpeed(intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed())); + switch (intent.getStringExtra(INTENT_TYPE)) { + case SINGLE_STREAM: + handleSinglePlaylistIntent(intent); + break; + case EXTERNAL_PLAYLIST: + handleExternalPlaylistIntent(intent); + break; + default: + break; + } + initThumbnail(); - //play(getSelectedVideoStream(), true); + } + + + @SuppressWarnings("unchecked") + public void handleExternalPlaylistIntent(Intent intent) { + final int serviceId = intent.getIntExtra(ExternalPlayQueue.SERVICE_ID, -1); + final int index = intent.getIntExtra(ExternalPlayQueue.INDEX, 0); + final Serializable serializable = intent.getSerializableExtra(ExternalPlayQueue.STREAMS); + final String nextPageUrl = intent.getStringExtra(ExternalPlayQueue.NEXT_PAGE_URL); + + List info = new ArrayList<>(); + if (serializable instanceof List) { + for (final Object o : (List) serializable) { + if (o instanceof InfoItem) info.add((StreamInfoItem) o); + } + } + + playQueue = new ExternalPlayQueue(serviceId, nextPageUrl, info, index); + playQueue.init(); + + playbackManager = new MediaSourceManager(this, playQueue); + } + + @SuppressWarnings("unchecked") + public void handleSinglePlaylistIntent(Intent intent) { + final Serializable serializable = intent.getSerializableExtra(SinglePlayQueue.STREAM); + if (!(serializable instanceof StreamInfo)) return; + + playQueue = new SinglePlayQueue((StreamInfo) serializable, PlayQueueItem.DEFAULT_QUALITY); + playQueue.init(); + + playbackManager = new MediaSourceManager(this, playQueue); } public void initThumbnail() { @@ -247,27 +302,6 @@ public abstract class BasePlayer implements Player.EventListener, }); } - public void playUrl(String url, String format, boolean autoPlay) { - if (DEBUG) { - Log.d(TAG, "play() called with: url = [" + url + "], autoPlay = [" + autoPlay + "]"); - } - - if (url == null || simpleExoPlayer == null) { - RuntimeException runtimeException = new RuntimeException((url == null ? "Url " : "Player ") + " null"); - onError(runtimeException); - throw runtimeException; - } - - changeState(STATE_LOADING); - - isPrepared = false; - - if (simpleExoPlayer.getPlaybackState() != Player.STATE_IDLE) simpleExoPlayer.stop(); - if (videoStartPos > 0) simpleExoPlayer.seekTo(videoStartPos); - simpleExoPlayer.prepare(mediaSource); - simpleExoPlayer.setPlayWhenReady(autoPlay); - } - public void destroyPlayer() { if (DEBUG) Log.d(TAG, "destroyPlayer() called"); if (simpleExoPlayer != null) { @@ -466,7 +500,6 @@ public abstract class BasePlayer implements Player.EventListener, public void onRepeatClicked() { if (DEBUG) Log.d(TAG, "onRepeatClicked() called"); - // TODO: implement repeat all when playlist is implemented final int mode; @@ -482,7 +515,7 @@ public abstract class BasePlayer implements Player.EventListener, mode = Player.REPEAT_MODE_OFF; break; } - // Switch the modes between DISABLED and REPEAT_ONE, till playlist is implemented + simpleExoPlayer.setRepeatMode(mode); if (DEBUG) Log.d(TAG, "onRepeatClicked() currentRepeatMode = " + simpleExoPlayer.getRepeatMode()); } @@ -566,8 +599,6 @@ public abstract class BasePlayer implements Player.EventListener, Log.d(TAG, "Blocking..."); simpleExoPlayer.stop(); - windowIndex = simpleExoPlayer.getCurrentWindowIndex(); - windowPos = Math.max(0, simpleExoPlayer.getContentPosition()); changeState(STATE_BUFFERING); } @@ -576,42 +607,51 @@ public abstract class BasePlayer implements Player.EventListener, public void unblock() { Log.d(TAG, "Unblocking..."); - if (windowIndex != playbackManager.getCurrentSourceIndex()) { - windowIndex = playbackManager.getCurrentSourceIndex(); - windowPos = 0; + if (restoreQueueIndex != playQueue.getIndex()) { + restoreQueueIndex = playQueue.getIndex(); + restoreWindowPos = 0; } simpleExoPlayer.prepare(playbackManager.getMediaSource()); - simpleExoPlayer.seekTo(windowIndex, windowPos); - simpleExoPlayer.setPlayWhenReady(true); + simpleExoPlayer.seekTo(playbackManager.getCurrentSourceIndex(), restoreWindowPos); + simpleExoPlayer.setPlayWhenReady(false); } @Override - public void sync(final int windowIndex, final StreamInfo info) { + public void sync(final StreamInfo info, final int sortedStreamsIndex) { Log.d(TAG, "Syncing..."); videoUrl = info.url; videoThumbnailUrl = info.thumbnail_url; videoTitle = info.name; - if (simpleExoPlayer.getCurrentWindowIndex() != windowIndex) { + if (simpleExoPlayer.getCurrentWindowIndex() != playbackManager.getCurrentSourceIndex()) { Log.w(TAG, "Rewinding to correct window"); - simpleExoPlayer.seekTo(windowIndex, 0L); + simpleExoPlayer.seekTo(playbackManager.getCurrentSourceIndex(), 0L); } + + simpleExoPlayer.setPlayWhenReady(true); } @Override - public MediaSource sourceOf(final StreamInfo info) { + public MediaSource sourceOf(final StreamInfo info, final int sortedStreamsIndex) { return null; } + @Override + public void shutdown() { + Log.d(TAG, "Shutting down..."); + + playbackManager.dispose(); + playQueue.dispose(); + destroy(); + } + /*////////////////////////////////////////////////////////////////////////// // General Player //////////////////////////////////////////////////////////////////////////*/ - public void onError(Exception exception){ - destroy(); - } + public abstract void onError(Exception exception); public void onPrepared(boolean playWhenReady) { if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]"); @@ -840,4 +880,12 @@ public abstract class BasePlayer implements Player.EventListener, public void setPlaybackSpeed(float speed) { simpleExoPlayer.setPlaybackParameters(new PlaybackParameters(speed, 1f)); } + + public int getCurrentQueueIndex() { + return playQueue != null ? playQueue.getIndex() : -1; + } + + public PlayQueue getPlayQueue() { + return playQueue; + } } diff --git a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java index 16329be9b..a6d647a49 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -123,7 +123,8 @@ public class MainVideoPlayer extends Activity { if (activityPaused) { playerImpl.initPlayer(); playerImpl.getPlayPauseButton().setImageResource(R.drawable.ic_play_arrow_white); - playerImpl.play(false); + playerImpl.playQueue.init(); + //playerImpl.play(false); activityPaused = false; } } @@ -230,21 +231,25 @@ public class MainVideoPlayer extends Activity { channelTextView.setText(getUploaderName()); } + /*////////////////////////////////////////////////////////////////////////// + // Playback Listener + //////////////////////////////////////////////////////////////////////////*/ + @Override - public void sync(final int windowIndex, final StreamInfo info) { - super.sync(windowIndex, info); + public void shutdown() { + super.shutdown(); + finish(); + } + + @Override + public void sync(final StreamInfo info, final int sortedStreamsIndex) { + super.sync(info, sortedStreamsIndex); titleTextView.setText(getVideoTitle()); channelTextView.setText(getUploaderName()); playPauseButton.setImageResource(R.drawable.ic_pause_white); } - @Override - public void playUrl(String url, String format, boolean autoPlay) { - super.playUrl(url, format, autoPlay); - playPauseButton.setImageResource(autoPlay ? R.drawable.ic_pause_white : R.drawable.ic_play_arrow_white); - } - @Override public void onFullScreenButtonClicked() { if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called"); @@ -331,7 +336,6 @@ public class MainVideoPlayer extends Activity { public void onError(Exception exception) { exception.printStackTrace(); Toast.makeText(context, "Failed to play this video", Toast.LENGTH_SHORT).show(); - //finish(); } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/player/MediaSourceManager.java b/app/src/main/java/org/schabi/newpipe/player/MediaSourceManager.java index 5f2ef03d8..c7e9fb64d 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MediaSourceManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/MediaSourceManager.java @@ -1,7 +1,6 @@ package org.schabi.newpipe.player; import android.support.annotation.Nullable; -import android.util.Log; import com.google.android.exoplayer2.source.DynamicConcatenatingMediaSource; import com.google.android.exoplayer2.source.MediaSource; @@ -19,7 +18,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import io.reactivex.MaybeObserver; import io.reactivex.SingleObserver; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.annotations.NonNull; @@ -67,13 +65,15 @@ class MediaSourceManager { * Signals to the listener to synchronize the player's window to the manager's * window. * */ - void sync(final int windowIndex, final StreamInfo info); + void sync(final StreamInfo info, final int sortedStreamsIndex); /* * 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, final int sortedStreamsIndex); + + void shutdown(); } MediaSourceManager(@NonNull final MediaSourceManager.PlaybackListener listener, @@ -118,9 +118,7 @@ class MediaSourceManager { void report(final Exception error) { // ignore error checking for now, just remove the current index - if (error != null) { - tryBlock(); - } + if (error == null || !tryBlock()) return; final int index = playQueue.getIndex(); playQueue.remove(index); @@ -129,6 +127,19 @@ class MediaSourceManager { load(); } + int queueIndexOf(final int sourceIndex) { + return sourceIndex < sourceToQueueIndex.size() ? sourceToQueueIndex.get(sourceIndex) : -1; + } + + void updateCurrent(final int newSortedStreamsIndex) { + if (!tryBlock()) return; + + PlayQueueItem item = playQueue.getCurrent(); + item.setSortedQualityIndex(newSortedStreamsIndex); + resetSources(); + load(); + } + void dispose() { if (loadingReactor != null) loadingReactor.cancel(); if (playQueueReactor != null) playQueueReactor.cancel(); @@ -180,7 +191,10 @@ class MediaSourceManager { if (!isPlayQueueReady()) { tryBlock(); playQueue.fetch(); + } else if (playQueue.isEmpty()) { + playbackListener.shutdown(); } + if (playQueueReactor != null) playQueueReactor.request(1); } @@ -240,14 +254,16 @@ class MediaSourceManager { } private void sync() { + final PlayQueueItem currentItem = playQueue.getCurrent(); + final Consumer onSuccess = new Consumer() { @Override public void accept(StreamInfo streamInfo) throws Exception { - playbackListener.sync(getCurrentSourceIndex(), streamInfo); + playbackListener.sync(streamInfo, currentItem.getSortedQualityIndex()); } }; - playQueue.getCurrent().getStream().subscribe(onSuccess); + currentItem.getStream().subscribe(onSuccess); } private void load() { @@ -280,7 +296,7 @@ class MediaSourceManager { @Override public void onSuccess(@NonNull StreamInfo streamInfo) { - final MediaSource source = playbackListener.sourceOf(streamInfo); + final MediaSource source = playbackListener.sourceOf(streamInfo, item.getSortedQualityIndex()); insert(playQueue.indexOf(item), source); if (tryUnblock()) sync(); } @@ -305,13 +321,12 @@ class MediaSourceManager { // Media Source List Manipulation //////////////////////////////////////////////////////////////////////////*/ - public void replace(final int queueIndex, final MediaSource source) { + private void reset(final int queueIndex) { 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); + sourceToQueueIndex.remove(sourceIndex); sources.removeMediaSource(sourceIndex); } } diff --git a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java index c00fee3d3..9d4fa8caa 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -272,10 +272,11 @@ public class PopupVideoPlayer extends Service { notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 77); break; case Player.REPEAT_MODE_ONE: - notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); + //todo change image + notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 168); break; case Player.REPEAT_MODE_ALL: - // Waiting :) + notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); break; } @@ -390,18 +391,6 @@ public class PopupVideoPlayer extends Service { super("VideoPlayerImpl" + PopupVideoPlayer.TAG, PopupVideoPlayer.this); } - @Override - public void playUrl(String url, String format, boolean autoPlay) { - super.playUrl(url, format, autoPlay); - - windowLayoutParams.width = (int) popupWidth; - windowLayoutParams.height = (int) getMinimumVideoHeight(popupWidth); - windowManager.updateViewLayout(getRootView(), windowLayoutParams); - - notBuilder = createNotification(); - startForeground(NOTIFICATION_ID, notBuilder.build()); - } - @Override public void initViews(View rootView) { super.initViews(rootView); @@ -475,7 +464,6 @@ public class PopupVideoPlayer extends Service { public void onError(Exception exception) { exception.printStackTrace(); Toast.makeText(context, "Failed to play this video", Toast.LENGTH_SHORT).show(); - stopSelf(); } @Override @@ -486,6 +474,16 @@ public class PopupVideoPlayer extends Service { } } + /*////////////////////////////////////////////////////////////////////////// + // Playback Listener + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void shutdown() { + super.shutdown(); + stopSelf(); + } + /*////////////////////////////////////////////////////////////////////////// // Broadcast Receiver //////////////////////////////////////////////////////////////////////////*/ @@ -583,8 +581,14 @@ public class PopupVideoPlayer extends Service { if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY()); if (!playerImpl.isPlaying()) return false; - if (e.getX() > popupWidth / 2) playerImpl.onFastForward(); - else playerImpl.onFastRewind(); + if (e.getX() > popupWidth / 2) { + //playerImpl.onFastForward(); + playerImpl.playQueue.setIndex(playerImpl.playQueue.getIndex() + 1); + } else { + //playerImpl.onFastRewind(); + playerImpl.playQueue.setIndex(playerImpl.playQueue.getIndex() - 1); + } + return true; } @@ -766,7 +770,7 @@ public class PopupVideoPlayer extends Service { mainHandler.post(new Runnable() { @Override public void run() { - playerImpl.play(true); + playerImpl.playQueue.init(); } }); diff --git a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java index 1be94a0e3..335ace207 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -53,13 +53,13 @@ import com.google.android.exoplayer2.source.MergingMediaSource; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.stream.AudioStream; -import org.schabi.newpipe.extractor.stream.StreamInfoItem; -import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.StreamInfo; -import org.schabi.newpipe.playlist.ExternalPlayQueue; +import org.schabi.newpipe.extractor.stream.VideoStream; +import org.schabi.newpipe.playlist.PlayQueue; +import org.schabi.newpipe.playlist.PlayQueueItem; +import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.util.AnimationUtils; import org.schabi.newpipe.util.ListHelper; @@ -89,7 +89,10 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. public static final String INDEX_SEL_VIDEO_STREAM = "index_selected_video_stream"; public static final String STARTED_FROM_NEWPIPE = "started_from_newpipe"; - private int selectedIndexStream; + public static final String PLAY_QUEUE = "play_queue"; + public static final String PLAYER_INTENT = "player_intent"; + + private int selectedIndexStream = -1; private ArrayList videoStreamsList = new ArrayList<>(); private AudioStream videoOnlyAudioStream; @@ -202,65 +205,55 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. simpleExoPlayer.setVideoListener(this); } - @SuppressWarnings("unchecked") - public void handleSingleStreamIntent(Intent 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) serializable; - if (serializable instanceof Vector) videoStreamsList = new ArrayList<>((List) 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") public void handleIntent(Intent intent) { super.handleIntent(intent); if (intent == null) return; - handleExternalPlaylistIntent(intent); + if (intent.getStringExtra(INTENT_TYPE).equals(PLAYER_INTENT)) { + handlePlayerIntent(intent); + } } @SuppressWarnings("unchecked") - public void handleExternalPlaylistIntent(Intent intent) { - selectedIndexStream = 0; + public void handleSinglePlaylistIntent(Intent intent) { + final Serializable serializable = intent.getSerializableExtra(SinglePlayQueue.STREAM); + if (!(serializable instanceof StreamInfo)) return; - final int serviceId = intent.getIntExtra("serviceId", -1); - final int index = intent.getIntExtra("index", 0); - final Serializable serializable = intent.getSerializableExtra("streams"); - final String nextPageUrl = intent.getStringExtra("nextPageUrl"); + final int sortedStreamsIndex = intent.getIntExtra(INDEX_SEL_VIDEO_STREAM, -1); - List info = new ArrayList<>(); - if (serializable instanceof List) { - for (final Object o : (List) serializable) { - if (o instanceof InfoItem) info.add((StreamInfoItem) o); - } - } + playQueue = new SinglePlayQueue((StreamInfo) serializable, sortedStreamsIndex); + playQueue.init(); - playQueue = new ExternalPlayQueue(serviceId, nextPageUrl, info, index); playbackManager = new MediaSourceManager(this, playQueue); } - public void play(boolean autoPlay) { - playUrl(getSelectedVideoStream().url, MediaFormat.getSuffixById(getSelectedVideoStream().format), autoPlay); + @SuppressWarnings("unchecked") + public void handlePlayerIntent(Intent intent) { + final Serializable serializable = intent.getSerializableExtra(PLAY_QUEUE); + if (!(serializable instanceof PlayQueue)) return; + + selectedIndexStream = intent.getIntExtra(INDEX_SEL_VIDEO_STREAM, -1); + + playQueue = (PlayQueue) serializable; + playQueue.init(); + + playbackManager = new MediaSourceManager(this, playQueue); } @Override - public void sync(final int windowIndex, final StreamInfo info) { - super.sync(windowIndex, info); + public void sync(final StreamInfo info, final int sortedStreamsIndex) { + super.sync(info, sortedStreamsIndex); final List videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); videoStreamsList = new ArrayList<>(videos); - selectedIndexStream = ListHelper.getDefaultResolutionIndex(context, videos); + + if (sortedStreamsIndex == PlayQueueItem.DEFAULT_QUALITY) { + selectedIndexStream = ListHelper.getDefaultResolutionIndex(context, videos); + } else { + selectedIndexStream = sortedStreamsIndex; + } qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId); buildQualityMenu(qualityPopupMenu); @@ -270,9 +263,16 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. } @Override - public MediaSource sourceOf(final StreamInfo info) { + public MediaSource sourceOf(final StreamInfo info, final int sortedStreamsIndex) { final List videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); - final VideoStream video = videos.get(ListHelper.getDefaultResolutionIndex(context, videos)); + + final VideoStream video; + if (sortedStreamsIndex == PlayQueueItem.DEFAULT_QUALITY) { + final int index = ListHelper.getDefaultResolutionIndex(context, videos); + video = videos.get(index); + } else { + video = videos.get(sortedStreamsIndex); + } final MediaSource mediaSource = super.buildMediaSource(video.url, MediaFormat.getSuffixById(video.format)); if (!video.isVideoOnly) return mediaSource; @@ -282,26 +282,6 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. return new MergingMediaSource(mediaSource, new ExtractorMediaSource(audioUri, cacheDataSourceFactory, extractorsFactory, null, null)); } - @Override - public void playUrl(String url, String format, boolean autoPlay) { - if (DEBUG) Log.d(TAG, "play() called with: url = [" + url + "], autoPlay = [" + autoPlay + "]"); - qualityChanged = false; - - if (url == null || simpleExoPlayer == null) { - RuntimeException runtimeException = new RuntimeException((url == null ? "Url " : "Player ") + " null"); - onError(runtimeException); - throw runtimeException; - } - - qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId); - buildQualityMenu(qualityPopupMenu); - - playbackSpeedPopupMenu.getMenu().removeGroup(playbackSpeedPopupMenuGroupId); - buildPlaybackSpeedMenu(playbackSpeedPopupMenu); - - super.playUrl(url, format, autoPlay); - } - @Override public MediaSource buildMediaSource(String url, String overrideExtension) { MediaSource mediaSource = super.buildMediaSource(url, overrideExtension); @@ -460,6 +440,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. if (duration != playbackSeekBar.getMax()) { playbackEndTime.setText(getTimeString(duration)); + playbackSeekBar.setMax(duration); } if (currentState != STATE_PAUSED) { if (currentState != STATE_PAUSED_SEEK) playbackSeekBar.setProgress(currentProgress); @@ -478,7 +459,7 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. if (DEBUG) Log.d(TAG, "onVideoPlayPauseRepeat() called"); if (qualityChanged) { setVideoStartPos(0); - play(true); + //play(true); } else super.onVideoPlayPauseRepeat(); } @@ -528,11 +509,10 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. if (qualityPopupMenuGroupId == menuItem.getGroupId()) { if (selectedIndexStream == menuItem.getItemId()) return true; - setVideoStartPos(simpleExoPlayer.getCurrentPosition()); - selectedIndexStream = menuItem.getItemId(); - if (!(getCurrentState() == STATE_COMPLETED)) play(wasPlaying); - else qualityChanged = true; + restoreQueueIndex = playQueue.getIndex(); + restoreWindowPos = simpleExoPlayer.getCurrentPosition(); + playbackManager.updateCurrent(menuItem.getItemId()); qualityTextView.setText(menuItem.getTitle()); return true; diff --git a/app/src/main/java/org/schabi/newpipe/playlist/ExternalPlayQueue.java b/app/src/main/java/org/schabi/newpipe/playlist/ExternalPlayQueue.java index 6615bd9f0..179c9e6c0 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/ExternalPlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/ExternalPlayQueue.java @@ -4,7 +4,6 @@ import android.util.Log; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; -import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.util.ExtractorHelper; @@ -18,8 +17,14 @@ import io.reactivex.annotations.NonNull; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -public class ExternalPlayQueue extends PlayQueue { +public final class ExternalPlayQueue extends PlayQueue { private final String TAG = "ExternalPlayQueue@" + Integer.toHexString(hashCode()); + + public static final String SERVICE_ID = "service_id"; + public static final String INDEX = "index"; + public static final String STREAMS = "streams"; + public static final String NEXT_PAGE_URL = "next_page_url"; + private static final int RETRY_COUNT = 2; private boolean isComplete; @@ -27,7 +32,7 @@ public class ExternalPlayQueue extends PlayQueue { private int serviceId; private String playlistUrl; - private Disposable fetchReactor; + private transient Disposable fetchReactor; public ExternalPlayQueue(final int serviceId, final String nextPageUrl, @@ -46,12 +51,6 @@ public class ExternalPlayQueue extends PlayQueue { return isComplete; } - @Override - public PlayQueueItem get(int index) { - if (index > getStreams().size() || getStreams().get(index) == null) return null; - return getStreams().get(index); - } - @Override public void fetch() { ExtractorHelper.getMorePlaylistItems(this.serviceId, this.playlistUrl) 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 bfb01cb23..aee56230c 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java @@ -16,6 +16,7 @@ import org.schabi.newpipe.playlist.events.RemoveEvent; import org.schabi.newpipe.playlist.events.SelectEvent; import org.schabi.newpipe.playlist.events.SwapEvent; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -26,27 +27,33 @@ import io.reactivex.BackpressureStrategy; import io.reactivex.Flowable; import io.reactivex.subjects.BehaviorSubject; -public abstract class PlayQueue { +public abstract class PlayQueue implements Serializable { private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode()); public static final boolean DEBUG = true; - private final List streams; + private final ArrayList streams; private final AtomicInteger queueIndex; - private final BehaviorSubject eventBroadcast; - private final Flowable broadcastReceiver; - private Subscription reportingReactor; + private transient BehaviorSubject eventBroadcast; + private transient Flowable broadcastReceiver; + private transient Subscription reportingReactor; PlayQueue() { this(0, Collections.emptyList()); } PlayQueue(final int index, final List startWith) { - streams = Collections.synchronizedList(new ArrayList()); + streams = new ArrayList<>(); streams.addAll(startWith); queueIndex = new AtomicInteger(index); + } + /*////////////////////////////////////////////////////////////////////////// + // Playlist actions + //////////////////////////////////////////////////////////////////////////*/ + + public void init() { eventBroadcast = BehaviorSubject.create(); broadcastReceiver = eventBroadcast .startWith(new InitEvent()) @@ -55,9 +62,12 @@ public abstract class PlayQueue { if (DEBUG) broadcastReceiver.subscribe(getSelfReporter()); } - /*////////////////////////////////////////////////////////////////////////// - // Playlist actions - //////////////////////////////////////////////////////////////////////////*/ + public void dispose() { + eventBroadcast.onComplete(); + + if (reportingReactor != null) reportingReactor.cancel(); + reportingReactor = null; + } // a queue is complete if it has loaded all items in an external playlist // single stream or local queues are always complete @@ -66,21 +76,27 @@ public abstract class PlayQueue { // load partial queue in the background, does nothing if the queue is complete public abstract void fetch(); - public abstract PlayQueueItem get(int index); - - public void dispose() { - eventBroadcast.onComplete(); - - if (reportingReactor != null) reportingReactor.cancel(); - reportingReactor = null; - } - /*////////////////////////////////////////////////////////////////////////// // Readonly ops //////////////////////////////////////////////////////////////////////////*/ + public int getIndex() { + return queueIndex.get(); + } + public PlayQueueItem getCurrent() { - return streams.get(getIndex()); + return get(getIndex()); + } + + public PlayQueueItem get(int index) { + if (index >= streams.size() || streams.get(index) == null) return null; + return streams.get(index); + } + + public int indexOf(final PlayQueueItem item) { + // reference equality, can't think of a better way to do this + // todo: better than this + return streams.indexOf(item); } public int size() { @@ -101,36 +117,26 @@ public abstract class PlayQueue { return broadcastReceiver; } - public int indexOf(final PlayQueueItem item) { - // reference equality, can't think of a better way to do this - // todo: better than this - return streams.indexOf(item); - } - - public int getIndex() { - return queueIndex.get(); - } - /*////////////////////////////////////////////////////////////////////////// // Write ops //////////////////////////////////////////////////////////////////////////*/ - public void setIndex(final int index) { + public synchronized void setIndex(final int index) { queueIndex.set(Math.min(Math.max(0, index), streams.size() - 1)); broadcast(new SelectEvent(index)); } - protected void append(final PlayQueueItem item) { + protected synchronized void append(final PlayQueueItem item) { streams.add(item); broadcast(new AppendEvent(1)); } - protected void append(final Collection items) { + protected synchronized void append(final Collection items) { streams.addAll(items); broadcast(new AppendEvent(items.size())); } - public void remove(final int index) { + public synchronized void remove(final int index) { if (index >= streams.size()) return; streams.remove(index); @@ -142,7 +148,7 @@ public abstract class PlayQueue { broadcast(new RemoveEvent(index)); } - protected void swap(final int source, final int target) { + protected synchronized void swap(final int source, final int target) { final List items = streams; if (source < items.size() && target < items.size()) { // Swap two items diff --git a/app/src/main/java/org/schabi/newpipe/playlist/PlayQueueItem.java b/app/src/main/java/org/schabi/newpipe/playlist/PlayQueueItem.java index f973f349e..80e1341e3 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/PlayQueueItem.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/PlayQueueItem.java @@ -7,20 +7,35 @@ import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.util.ExtractorHelper; +import java.io.Serializable; + import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.functions.Consumer; import io.reactivex.schedulers.Schedulers; -public class PlayQueueItem { +public class PlayQueueItem implements Serializable { + + final public static int DEFAULT_QUALITY = -1; final private String title; final private String url; final private int serviceId; final private long duration; + // Externally mutable, not sure if this is a good idea here + private int sortedQualityIndex; + private Throwable error; - private Single stream; + + PlayQueueItem(final StreamInfo streamInfo, final int sortedQualityIndex) { + this.title = streamInfo.name; + this.url = streamInfo.url; + this.serviceId = streamInfo.service_id; + this.duration = streamInfo.duration; + + this.sortedQualityIndex = sortedQualityIndex; + } PlayQueueItem(final StreamInfoItem streamInfoItem) { this.title = streamInfoItem.name; @@ -28,9 +43,10 @@ public class PlayQueueItem { this.serviceId = streamInfoItem.service_id; this.duration = streamInfoItem.duration; - this.stream = getInfo(); + this.sortedQualityIndex = DEFAULT_QUALITY; } + @NonNull public String getTitle() { return title; @@ -49,6 +65,14 @@ public class PlayQueueItem { return duration; } + public int getSortedQualityIndex() { + return sortedQualityIndex; + } + + public void setSortedQualityIndex(int sortedQualityIndex) { + this.sortedQualityIndex = sortedQualityIndex; + } + @Nullable public Throwable getError() { return error; @@ -56,11 +80,6 @@ public class PlayQueueItem { @NonNull public Single getStream() { - return stream; - } - - @NonNull - private Single getInfo() { final Consumer onError = new Consumer() { @Override public void accept(Throwable throwable) throws Exception { diff --git a/app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java b/app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java new file mode 100644 index 000000000..5fe141881 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/playlist/SinglePlayQueue.java @@ -0,0 +1,21 @@ +package org.schabi.newpipe.playlist; + +import org.schabi.newpipe.extractor.stream.StreamInfo; + +import java.util.Collections; + +public final class SinglePlayQueue extends PlayQueue { + public static final String STREAM = "stream"; + + public SinglePlayQueue(final StreamInfo info, final int selectedQualityIndex) { + super(0, Collections.singletonList(new PlayQueueItem(info, selectedQualityIndex))); + } + + @Override + public boolean isComplete() { + return true; + } + + @Override + public void fetch() {} +} diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index b08251436..2af8fb907 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -13,10 +13,12 @@ import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; import org.schabi.newpipe.about.AboutActivity; import org.schabi.newpipe.download.DownloadActivity; +import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.fragments.MainFragment; @@ -30,9 +32,12 @@ import org.schabi.newpipe.history.HistoryActivity; import org.schabi.newpipe.player.BackgroundPlayer; import org.schabi.newpipe.player.BasePlayer; import org.schabi.newpipe.player.VideoPlayer; +import org.schabi.newpipe.playlist.ExternalPlayQueue; +import org.schabi.newpipe.playlist.SinglePlayQueue; import org.schabi.newpipe.settings.SettingsActivity; import java.util.ArrayList; +import java.util.List; @SuppressWarnings({"unused", "WeakerAccess"}) public class NavigationHelper { @@ -43,46 +48,60 @@ public class NavigationHelper { //////////////////////////////////////////////////////////////////////////*/ public static Intent getOpenVideoPlayerIntent(Context context, Class targetClazz, StreamInfo info, int selectedStreamIndex) { - Intent mIntent = new Intent(context, targetClazz) - .putExtra(BasePlayer.VIDEO_TITLE, info.name) - .putExtra(BasePlayer.VIDEO_URL, info.url) - .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, info.thumbnail_url) - .putExtra(BasePlayer.CHANNEL_NAME, info.uploader_name) - .putExtra(VideoPlayer.INDEX_SEL_VIDEO_STREAM, selectedStreamIndex) - .putExtra(VideoPlayer.VIDEO_STREAMS_LIST, new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false))) - .putExtra(VideoPlayer.VIDEO_ONLY_AUDIO_STREAM, ListHelper.getHighestQualityAudio(info.audio_streams)); - if (info.start_position > 0) mIntent.putExtra(BasePlayer.START_POSITION, info.start_position * 1000L); - return mIntent; + return new Intent(context, targetClazz) + .putExtra(BasePlayer.INTENT_TYPE, VideoPlayer.SINGLE_STREAM) + .putExtra(SinglePlayQueue.STREAM, info) + .putExtra(VideoPlayer.INDEX_SEL_VIDEO_STREAM, selectedStreamIndex); + } + + public static Intent getExternalPlaylistIntent(Context context, + Class targetClazz, + PlaylistInfo info, + ArrayList streams, + int index) { + return new Intent(context, targetClazz) + .putExtra(BasePlayer.INTENT_TYPE, VideoPlayer.EXTERNAL_PLAYLIST) + .putExtra(ExternalPlayQueue.SERVICE_ID, info.service_id) + .putExtra(ExternalPlayQueue.INDEX, index) + .putExtra(ExternalPlayQueue.STREAMS, streams) + .putExtra(ExternalPlayQueue.NEXT_PAGE_URL, info.next_streams_url); } public static Intent getOpenVideoPlayerIntent(Context context, Class targetClazz, VideoPlayer instance) { return new Intent(context, targetClazz) - .putExtra(BasePlayer.VIDEO_TITLE, instance.getVideoTitle()) - .putExtra(BasePlayer.VIDEO_URL, instance.getVideoUrl()) - .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, instance.getVideoThumbnailUrl()) - .putExtra(BasePlayer.CHANNEL_NAME, instance.getUploaderName()) + .putExtra(BasePlayer.INTENT_TYPE, VideoPlayer.PLAYER_INTENT) + .putExtra(VideoPlayer.PLAY_QUEUE, instance.getPlayQueue()) .putExtra(VideoPlayer.INDEX_SEL_VIDEO_STREAM, instance.getSelectedStreamIndex()) - .putExtra(VideoPlayer.VIDEO_STREAMS_LIST, instance.getVideoStreamsList()) - .putExtra(VideoPlayer.VIDEO_ONLY_AUDIO_STREAM, instance.getAudioStream()) + .putExtra(VideoPlayer.RESTORE_QUEUE_INDEX, instance.getCurrentQueueIndex()) .putExtra(BasePlayer.START_POSITION, instance.getPlayer().getCurrentPosition()) .putExtra(BasePlayer.PLAYBACK_SPEED, instance.getPlaybackSpeed()); } public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info) { - return getOpenBackgroundPlayerIntent(context, info, info.audio_streams.get(ListHelper.getDefaultAudioFormat(context, info.audio_streams))); + return new Intent(context, BackgroundPlayer.class) + .putExtra(BasePlayer.INTENT_TYPE, VideoPlayer.SINGLE_STREAM) + .putExtra(SinglePlayQueue.STREAM, info); } public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info, AudioStream audioStream) { - Intent mIntent = new Intent(context, BackgroundPlayer.class) - .putExtra(BasePlayer.VIDEO_TITLE, info.name) - .putExtra(BasePlayer.VIDEO_URL, info.url) - .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, info.thumbnail_url) - .putExtra(BasePlayer.CHANNEL_NAME, info.uploader_name) - .putExtra(BackgroundPlayer.AUDIO_STREAM, audioStream); - if (info.start_position > 0) mIntent.putExtra(BasePlayer.START_POSITION, info.start_position * 1000L); - return mIntent; + return getOpenBackgroundPlayerIntent(context, info); } +// public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info) { +// return getOpenBackgroundPlayerIntent(context, info, info.audio_streams.get(ListHelper.getDefaultAudioFormat(context, info.audio_streams))); +// } +// +// public static Intent getOpenBackgroundPlayerIntent(Context context, StreamInfo info, AudioStream audioStream) { +// Intent mIntent = new Intent(context, BackgroundPlayer.class) +// .putExtra(BasePlayer.VIDEO_TITLE, info.name) +// .putExtra(BasePlayer.VIDEO_URL, info.url) +// .putExtra(BasePlayer.VIDEO_THUMBNAIL_URL, info.thumbnail_url) +// .putExtra(BasePlayer.CHANNEL_NAME, info.uploader_name) +// .putExtra(BackgroundPlayer.AUDIO_STREAM, audioStream); +// if (info.start_position > 0) mIntent.putExtra(BasePlayer.START_POSITION, info.start_position * 1000L); +// return mIntent; +// } + /*////////////////////////////////////////////////////////////////////////// // Through FragmentManager //////////////////////////////////////////////////////////////////////////*/