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 8659ca645..b3c1fd037 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BackgroundPlayer.java @@ -35,6 +35,8 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.RemoteViews; +import com.google.android.exoplayer2.Player; + import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.R; @@ -192,15 +194,16 @@ public class BackgroundPlayer extends Service { remoteViews.setOnClickPendingIntent(R.id.notificationFForward, PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_FAST_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT)); - switch (basePlayerImpl.getCurrentRepeatMode()) { - case REPEAT_DISABLED: + switch (basePlayerImpl.simpleExoPlayer.getRepeatMode()) { + case Player.REPEAT_MODE_OFF: remoteViews.setInt(R.id.notificationRepeat, setAlphaMethodName, 77); break; - case REPEAT_ONE: + case Player.REPEAT_MODE_ONE: + // todo change image remoteViews.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); break; - case REPEAT_ALL: - // Waiting :) + case Player.REPEAT_MODE_ALL: + remoteViews.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); break; } } @@ -319,14 +322,15 @@ public class BackgroundPlayer extends Service { int opacity = 255; switch (currentRepeatMode) { - case REPEAT_DISABLED: + case Player.REPEAT_MODE_OFF: opacity = 77; break; - case REPEAT_ONE: - opacity = 255; + case Player.REPEAT_MODE_ONE: + // todo change image + opacity = 168; break; - case REPEAT_ALL: - // Waiting :) + case Player.REPEAT_MODE_ALL: + opacity = 255; break; } if (notRemoteView != null) notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, opacity); 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 2ea0d9860..48a9a7b99 100644 --- a/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/BasePlayer.java @@ -125,6 +125,9 @@ public abstract class BasePlayer implements Player.EventListener, protected MediaSourceManager playbackManager; protected PlayQueue playQueue; + private int windowIndex; + private long windowPos; + /*////////////////////////////////////////////////////////////////////////// // Player //////////////////////////////////////////////////////////////////////////*/ @@ -452,35 +455,36 @@ public abstract class BasePlayer implements Player.EventListener, public void onCompleted() { if (DEBUG) Log.d(TAG, "onCompleted() called"); if (isProgressLoopRunning.get()) stopProgressLoop(); - - if (currentRepeatMode == RepeatMode.REPEAT_ONE) { - changeState(STATE_LOADING); - simpleExoPlayer.seekTo(0); - } } /*////////////////////////////////////////////////////////////////////////// // Repeat //////////////////////////////////////////////////////////////////////////*/ - protected RepeatMode currentRepeatMode = RepeatMode.REPEAT_DISABLED; + protected int currentRepeatMode = Player.REPEAT_MODE_OFF; - public enum RepeatMode { - REPEAT_DISABLED, - REPEAT_ONE, - REPEAT_ALL - } public void onRepeatClicked() { if (DEBUG) Log.d(TAG, "onRepeatClicked() called"); // TODO: implement repeat all when playlist is implemented - // Switch the modes between DISABLED and REPEAT_ONE, till playlist is implemented - setCurrentRepeatMode(getCurrentRepeatMode() == RepeatMode.REPEAT_DISABLED ? - RepeatMode.REPEAT_ONE : - RepeatMode.REPEAT_DISABLED); + final int mode; - if (DEBUG) Log.d(TAG, "onRepeatClicked() currentRepeatMode = " + getCurrentRepeatMode().name()); + switch (simpleExoPlayer.getRepeatMode()) { + case Player.REPEAT_MODE_OFF: + mode = Player.REPEAT_MODE_ONE; + break; + case Player.REPEAT_MODE_ONE: + mode = Player.REPEAT_MODE_ALL; + break; + case Player.REPEAT_MODE_ALL: + default: + 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()); } /*////////////////////////////////////////////////////////////////////////// @@ -557,15 +561,10 @@ public abstract class BasePlayer implements Player.EventListener, // Playback Listener //////////////////////////////////////////////////////////////////////////*/ - private int windowIndex; - private long windowPos; - @Override public void block() { Log.d(TAG, "Blocking..."); - if (currentState != STATE_PLAYING) return; - simpleExoPlayer.stop(); windowIndex = simpleExoPlayer.getCurrentWindowIndex(); windowPos = Math.max(0, simpleExoPlayer.getContentPosition()); @@ -577,8 +576,6 @@ public abstract class BasePlayer implements Player.EventListener, public void unblock() { Log.d(TAG, "Unblocking..."); - if (currentState != STATE_BUFFERING) return; - if (windowIndex != playbackManager.getCurrentSourceIndex()) { windowIndex = playbackManager.getCurrentSourceIndex(); windowPos = 0; @@ -587,11 +584,10 @@ public abstract class BasePlayer implements Player.EventListener, simpleExoPlayer.prepare(playbackManager.getMediaSource()); simpleExoPlayer.seekTo(windowIndex, windowPos); simpleExoPlayer.setPlayWhenReady(true); - changeState(STATE_PLAYING); } @Override - public void sync(final int windowIndex, final long windowPos, final StreamInfo info) { + public void sync(final int windowIndex, final StreamInfo info) { Log.d(TAG, "Syncing..."); videoUrl = info.url; @@ -600,22 +596,10 @@ public abstract class BasePlayer implements Player.EventListener, if (simpleExoPlayer.getCurrentWindowIndex() != windowIndex) { Log.w(TAG, "Rewinding to correct window"); - simpleExoPlayer.seekTo(windowIndex, windowPos); - } else { - simpleExoPlayer.seekTo(windowPos); + simpleExoPlayer.seekTo(windowIndex, 0L); } } - @Override - public void init() { - Log.d(TAG, "Initializing..."); - - if (simpleExoPlayer.getPlaybackState() != Player.STATE_IDLE) simpleExoPlayer.stop(); - simpleExoPlayer.prepare(playbackManager.getMediaSource()); - simpleExoPlayer.seekToDefaultPosition(); - simpleExoPlayer.setPlayWhenReady(true); - } - @Override public MediaSource sourceOf(final StreamInfo info) { return null; @@ -785,14 +769,6 @@ public abstract class BasePlayer implements Player.EventListener, return sharedPreferences; } - public RepeatMode getCurrentRepeatMode() { - return currentRepeatMode; - } - - public void setCurrentRepeatMode(RepeatMode mode) { - currentRepeatMode = mode; - } - public int getCurrentState() { return currentState; } 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 663f532b2..16329be9b 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/MainVideoPlayer.java @@ -39,6 +39,8 @@ import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; +import com.google.android.exoplayer2.Player; + import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.util.AnimationUtils; @@ -229,8 +231,8 @@ public class MainVideoPlayer extends Activity { } @Override - public void sync(final int windowIndex, final long windowPos, final StreamInfo info) { - super.sync(windowIndex, windowPos, info); + public void sync(final int windowIndex, final StreamInfo info) { + super.sync(windowIndex, info); titleTextView.setText(getVideoTitle()); channelTextView.setText(getUploaderName()); @@ -266,19 +268,22 @@ public class MainVideoPlayer extends Activity { public void onRepeatClicked() { super.onRepeatClicked(); if (DEBUG) Log.d(TAG, "onRepeatClicked() called"); - switch (getCurrentRepeatMode()) { - case REPEAT_DISABLED: + switch (simpleExoPlayer.getRepeatMode()) { + case Player.REPEAT_MODE_OFF: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) repeatButton.setImageAlpha(77); else repeatButton.setAlpha(77); break; - case REPEAT_ONE: + case Player.REPEAT_MODE_ONE: + // todo change image + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) repeatButton.setImageAlpha(168); + else repeatButton.setAlpha(168); + + break; + case Player.REPEAT_MODE_ALL: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) repeatButton.setImageAlpha(255); else repeatButton.setAlpha(255); - break; - case REPEAT_ALL: - // Waiting :) break; } } @@ -387,18 +392,15 @@ public class MainVideoPlayer extends Activity { @Override public void onCompleted() { - if (getCurrentRepeatMode() == RepeatMode.REPEAT_ONE) { - playPauseButton.setImageResource(R.drawable.ic_pause_white); - } else { - showSystemUi(); - animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, new Runnable() { - @Override - public void run() { - playPauseButton.setImageResource(R.drawable.ic_replay_white); - animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, true, 300); - } - }); - } + showSystemUi(); + animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, false, 0, 0, new Runnable() { + @Override + public void run() { + playPauseButton.setImageResource(R.drawable.ic_replay_white); + animateView(playPauseButton, AnimationUtils.Type.SCALE_AND_ALPHA, true, 300); + } + }); + getRootView().setKeepScreenOn(false); super.onCompleted(); } 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 37fab1ef0..5f2ef03d8 100644 --- a/app/src/main/java/org/schabi/newpipe/player/MediaSourceManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/MediaSourceManager.java @@ -1,5 +1,6 @@ package org.schabi.newpipe.player; +import android.support.annotation.Nullable; import android.util.Log; import com.google.android.exoplayer2.source.DynamicConcatenatingMediaSource; @@ -48,13 +49,6 @@ class MediaSourceManager { private boolean isBlocked; 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(); - /* * Called when the stream at the current queue index is not ready yet. * Signals to the listener to block the player from playing anything. @@ -73,7 +67,7 @@ class MediaSourceManager { * 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 StreamInfo info); /* * Requests the listener to resolve a stream info into a media source respective @@ -132,7 +126,7 @@ class MediaSourceManager { playQueue.remove(index); resetSources(); - init(); + load(); } void dispose() { @@ -163,8 +157,7 @@ class MediaSourceManager { // why no pattern matching in Java =( switch (event.type()) { case INIT: - init(); - break; + isBlocked = true; case APPEND: load(); break; @@ -213,18 +206,22 @@ class MediaSourceManager { return getCurrentSourceIndex() != -1; } - private void tryBlock() { + private boolean tryBlock() { if (!isBlocked) { playbackListener.block(); isBlocked = true; + return true; } + return false; } - private void tryUnblock() { + private boolean tryUnblock() { if (isPlayQueueReady() && isCurrentIndexLoaded() && isBlocked) { isBlocked = false; playbackListener.unblock(); + return true; } + return false; } /* @@ -246,7 +243,7 @@ class MediaSourceManager { final Consumer onSuccess = new Consumer() { @Override public void accept(StreamInfo streamInfo) throws Exception { - playbackListener.sync(getCurrentSourceIndex(), 0L, streamInfo); + playbackListener.sync(getCurrentSourceIndex(), streamInfo); } }; @@ -254,9 +251,12 @@ class MediaSourceManager { } private void load() { + // The current item has higher priority final int currentIndex = playQueue.getIndex(); - load(playQueue.get(currentIndex)); + final PlayQueueItem currentItem = playQueue.get(currentIndex); + if (currentItem != null) load(currentItem); + // The rest are just for seamless playback final int leftBound = Math.max(0, currentIndex - WINDOW_SIZE); final int rightBound = Math.min(playQueue.size(), currentIndex + WINDOW_SIZE); final List items = playQueue.getStreams().subList(leftBound, rightBound); @@ -265,42 +265,9 @@ class MediaSourceManager { } } - private void init() { - final PlayQueueItem init = playQueue.getCurrent(); + private void load(@Nullable final PlayQueueItem item) { + if (item == null) return; - init.getStream().subscribe(new SingleObserver() { - @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(); - } - }); - } - - private void load(final PlayQueueItem item) { item.getStream().subscribe(new SingleObserver() { @Override public void onSubscribe(@NonNull Disposable d) { @@ -315,7 +282,7 @@ class MediaSourceManager { public void onSuccess(@NonNull StreamInfo streamInfo) { final MediaSource source = playbackListener.sourceOf(streamInfo); insert(playQueue.indexOf(item), source); - tryUnblock(); + if (tryUnblock()) sync(); } @Override 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 a4087a942..c00fee3d3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/PopupVideoPlayer.java @@ -49,6 +49,7 @@ import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; +import com.google.android.exoplayer2.Player; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; @@ -266,14 +267,14 @@ public class PopupVideoPlayer extends Service { notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat, PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT)); - switch (playerImpl.getCurrentRepeatMode()) { - case REPEAT_DISABLED: + switch (playerImpl.simpleExoPlayer.getRepeatMode()) { + case Player.REPEAT_MODE_OFF: notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 77); break; - case REPEAT_ONE: + case Player.REPEAT_MODE_ONE: notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); break; - case REPEAT_ALL: + case Player.REPEAT_MODE_ALL: // Waiting :) break; } @@ -446,18 +447,19 @@ public class PopupVideoPlayer extends Service { @Override public void onRepeatClicked() { super.onRepeatClicked(); - switch (getCurrentRepeatMode()) { - case REPEAT_DISABLED: + switch (simpleExoPlayer.getRepeatMode()) { + case Player.REPEAT_MODE_OFF: // Drawable didn't work on low API :/ //notRemoteView.setImageViewResource(R.id.notificationRepeat, R.drawable.ic_repeat_disabled_white); // Set the icon to 30% opacity - 255 (max) * .3 notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 77); break; - case REPEAT_ONE: - notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); + case Player.REPEAT_MODE_ONE: + // todo change image + notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 168); break; - case REPEAT_ALL: - // Waiting :) + case Player.REPEAT_MODE_ALL: + notRemoteView.setInt(R.id.notificationRepeat, setAlphaMethodName, 255); break; } updateNotification(-1); 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 028f85a43..1be94a0e3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/player/VideoPlayer.java @@ -204,7 +204,6 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. @SuppressWarnings("unchecked") public void handleSingleStreamIntent(Intent intent) { - super.handleIntent(intent); if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]"); if (intent == null) return; @@ -224,6 +223,8 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. @SuppressWarnings("unchecked") public void handleIntent(Intent intent) { + super.handleIntent(intent); + if (intent == null) return; handleExternalPlaylistIntent(intent); @@ -254,17 +255,15 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. } @Override - public void sync(final int windowIndex, final long windowPos, final StreamInfo info) { - super.sync(windowIndex, windowPos, info); + public void sync(final int windowIndex, final StreamInfo info) { + super.sync(windowIndex, info); + + final List videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); + videoStreamsList = new ArrayList<>(videos); + selectedIndexStream = ListHelper.getDefaultResolutionIndex(context, videos); qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId); - for (int i = 0; i < info.video_streams.size(); i++) { - VideoStream videoStream = info.video_streams.get(i); - qualityPopupMenu.getMenu().add(qualityPopupMenuGroupId, i, Menu.NONE, MediaFormat.getNameById(videoStream.format) + " " + videoStream.resolution); - } - qualityTextView.setText(info.video_streams.get(selectedIndexStream).resolution); - qualityPopupMenu.setOnMenuItemClickListener(this); - qualityPopupMenu.setOnDismissListener(this); + buildQualityMenu(qualityPopupMenu); playbackSpeedPopupMenu.getMenu().removeGroup(playbackSpeedPopupMenuGroupId); buildPlaybackSpeedMenu(playbackSpeedPopupMenu); @@ -409,11 +408,6 @@ public abstract class VideoPlayer extends BasePlayer implements SimpleExoPlayer. playbackSeekBar.getThumb().setColorFilter(Color.RED, PorterDuff.Mode.SRC_IN); animateView(surfaceForeground, true, 100); - - if (currentRepeatMode == RepeatMode.REPEAT_ONE) { - changeState(STATE_LOADING); - simpleExoPlayer.seekTo(0); - } } /*////////////////////////////////////////////////////////////////////////// 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 f2927e922..6615bd9f0 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/ExternalPlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/ExternalPlayQueue.java @@ -3,6 +3,7 @@ package org.schabi.newpipe.playlist; 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; @@ -53,15 +54,15 @@ public class ExternalPlayQueue extends PlayQueue { @Override public void fetch() { - ExtractorHelper.getPlaylistInfo(this.serviceId, this.playlistUrl, false) + ExtractorHelper.getMorePlaylistItems(this.serviceId, this.playlistUrl) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .retry(RETRY_COUNT) .subscribe(getPlaylistObserver()); } - private SingleObserver getPlaylistObserver() { - return new SingleObserver() { + private SingleObserver getPlaylistObserver() { + return new SingleObserver() { @Override public void onSubscribe(@NonNull Disposable d) { if (isComplete || (fetchReactor != null && !fetchReactor.isDisposed())) { @@ -72,11 +73,11 @@ public class ExternalPlayQueue extends PlayQueue { } @Override - public void onSuccess(@NonNull PlaylistInfo playlistInfo) { - if (!playlistInfo.has_more_streams) isComplete = true; - playlistUrl = playlistInfo.next_streams_url; + public void onSuccess(@NonNull ListExtractor.NextItemsResult result) { + if (!result.hasMoreStreams()) isComplete = true; + playlistUrl = result.nextItemsUrl; - append(extractPlaylistItems(playlistInfo.related_streams)); + append(extractPlaylistItems(result.nextItemsList)); } @Override 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 c32417ee2..bfb01cb23 100644 --- a/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java +++ b/app/src/main/java/org/schabi/newpipe/playlist/PlayQueue.java @@ -87,6 +87,10 @@ public abstract class PlayQueue { return streams.size(); } + public boolean isEmpty() { + return streams.isEmpty(); + } + @NonNull public List getStreams() { return Collections.unmodifiableList(streams);