From fd55d85bbf050bd0da7b6e1fd81f52a5a584613f Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Wed, 2 Nov 2022 20:39:33 +0530 Subject: [PATCH 1/4] Remove SimplifyOptionalCallChains. --- .../fragments/detail/VideoDetailFragment.java | 20 ++-- .../org/schabi/newpipe/player/Player.java | 90 ++++++++-------- .../player/playback/MediaSourceManager.java | 2 +- .../SeekbarPreviewThumbnailHelper.java | 19 ++-- .../newpipe/player/ui/MainPlayerUi.java | 10 +- .../newpipe/player/ui/VideoPlayerUi.java | 101 ++++++++---------- 6 files changed, 109 insertions(+), 133 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 679084bdf..abb995ecd 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -255,11 +255,8 @@ public final class VideoDetailFragment playerUi.ifPresent(MainPlayerUi::toggleFullscreen); } - //noinspection SimplifyOptionalCallChains - if (playAfterConnect - || (currentInfo != null - && isAutoplayEnabled() - && !playerUi.isPresent())) { + if (playAfterConnect || (currentInfo != null && isAutoplayEnabled() + && playerUi.isEmpty())) { autoPlayEnabled = true; // forcefully start playing openVideoPlayerAutoFullscreen(); } @@ -1174,16 +1171,15 @@ public final class VideoDetailFragment * be reused in a few milliseconds and the flickering would be annoying. */ private void hideMainPlayerOnLoadingNewStream() { - //noinspection SimplifyOptionalCallChains - if (!isPlayerServiceAvailable() || !getRoot().isPresent() - || !player.videoPlayerSelected()) { + final var root = getRoot(); + if (!isPlayerServiceAvailable() || root.isEmpty() || !player.videoPlayerSelected()) { return; } removeVideoPlayerView(); if (isAutoplayEnabled()) { playerService.stopForImmediateReusing(); - getRoot().ifPresent(view -> view.setVisibility(View.GONE)); + root.ifPresent(view -> view.setVisibility(View.GONE)); } else { playerHolder.stopService(); } @@ -1887,10 +1883,8 @@ public final class VideoDetailFragment @Override public void onFullscreenStateChanged(final boolean fullscreen) { setupBrightness(); - //noinspection SimplifyOptionalCallChains - if (!isPlayerAndPlayerServiceAvailable() - || !player.UIs().get(MainPlayerUi.class).isPresent() - || getRoot().map(View::getParent).orElse(null) == null) { + if (!isPlayerAndPlayerServiceAvailable() || player.UIs().get(MainPlayerUi.class).isEmpty() + || getRoot().map(View::getParent).isEmpty()) { return; } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 95520ba1e..da337b394 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1695,26 +1695,25 @@ public final class Player implements PlaybackListener, Listener { } private void saveStreamProgressState(final long progressMillis) { - //noinspection SimplifyOptionalCallChains - if (!getCurrentStreamInfo().isPresent() - || !prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)) { - return; - } - if (DEBUG) { - Log.d(TAG, "saveStreamProgressState() called with: progressMillis=" + progressMillis - + ", currentMetadata=[" + getCurrentStreamInfo().get().getName() + "]"); - } + getCurrentStreamInfo().ifPresent(info -> { + if (!prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)) { + return; + } + if (DEBUG) { + Log.d(TAG, "saveStreamProgressState() called with: progressMillis=" + progressMillis + + ", currentMetadata=[" + info.getName() + "]"); + } - databaseUpdateDisposable - .add(recordManager.saveStreamState(getCurrentStreamInfo().get(), progressMillis) - .observeOn(AndroidSchedulers.mainThread()) - .doOnError(e -> { - if (DEBUG) { - e.printStackTrace(); - } - }) - .onErrorComplete() - .subscribe()); + databaseUpdateDisposable.add(recordManager.saveStreamState(info, progressMillis) + .observeOn(AndroidSchedulers.mainThread()) + .doOnError(e -> { + if (DEBUG) { + e.printStackTrace(); + } + }) + .onErrorComplete() + .subscribe()); + }); } public void saveStreamProgressState() { @@ -2036,40 +2035,35 @@ public final class Player implements PlaybackListener, Listener { // in livestreams) so we will be not able to execute the block below. // Reload the play queue manager in this case, which is the behavior when we don't know the // index of the video renderer or playQueueManagerReloadingNeeded returns true. - final Optional optCurrentStreamInfo = getCurrentStreamInfo(); - if (!optCurrentStreamInfo.isPresent()) { - reloadPlayQueueManager(); - setRecovery(); - return; - } + getCurrentStreamInfo().ifPresentOrElse(info -> { + // In the case we don't know the source type, fallback to the one with video with audio + // or audio-only source. + final SourceType sourceType = videoResolver.getStreamSourceType() + .orElse(SourceType.VIDEO_WITH_AUDIO_OR_AUDIO_ONLY); - final StreamInfo info = optCurrentStreamInfo.get(); + if (playQueueManagerReloadingNeeded(sourceType, info, getVideoRendererIndex())) { + reloadPlayQueueManager(); + } else { + if (StreamTypeUtil.isAudio(info.getStreamType())) { + // Nothing to do more than setting the recovery position + setRecovery(); + return; + } - // In the case we don't know the source type, fallback to the one with video with audio or - // audio-only source. - final SourceType sourceType = videoResolver.getStreamSourceType().orElse( - SourceType.VIDEO_WITH_AUDIO_OR_AUDIO_ONLY); + final var parametersBuilder = trackSelector.buildUponParameters(); - if (playQueueManagerReloadingNeeded(sourceType, info, getVideoRendererIndex())) { - reloadPlayQueueManager(); - } else { - if (StreamTypeUtil.isAudio(info.getStreamType())) { - // Nothing to do more than setting the recovery position - setRecovery(); - return; + // Enable/disable the video track and the ability to select subtitles + parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, !videoEnabled); + parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, !videoEnabled); + + trackSelector.setParameters(parametersBuilder); } - final DefaultTrackSelector.Parameters.Builder parametersBuilder = - trackSelector.buildUponParameters(); - - // Enable/disable the video track and the ability to select subtitles - parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, !videoEnabled); - parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, !videoEnabled); - - trackSelector.setParameters(parametersBuilder); - } - - setRecovery(); + setRecovery(); + }, () -> { + reloadPlayQueueManager(); + setRecovery(); + }); } /** diff --git a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java index 9b13bb3d7..f58aa6e91 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java @@ -423,7 +423,7 @@ public class MediaSourceManager { private Single getLoadedMediaSource(@NonNull final PlayQueueItem stream) { return stream.getStream().map(streamInfo -> { final MediaSource source = playbackListener.sourceOf(stream, streamInfo); - if (source == null || !MediaItemTag.from(source.getMediaItem()).isPresent()) { + if (source == null || MediaItemTag.from(source.getMediaItem()).isEmpty()) { final String message = "Unable to resolve source from stream info. " + "URL: " + stream.getUrl() + ", " + "audio count: " + streamInfo.getAudioStreams().size() + ", " diff --git a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java index 9eea89e78..b7441c272 100644 --- a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java @@ -8,6 +8,7 @@ import android.widget.ImageView; import androidx.annotation.IntDef; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.core.graphics.BitmapCompat; import androidx.core.math.MathUtils; import androidx.preference.PreferenceManager; @@ -16,7 +17,6 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.util.DeviceUtils; import java.lang.annotation.Retention; -import java.util.Optional; import java.util.function.IntSupplier; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -66,21 +66,19 @@ public final class SeekbarPreviewThumbnailHelper { public static void tryResizeAndSetSeekbarPreviewThumbnail( @NonNull final Context context, - @NonNull final Optional optPreviewThumbnail, + @Nullable final Bitmap previewThumbnail, @NonNull final ImageView currentSeekbarPreviewThumbnail, @NonNull final IntSupplier baseViewWidthSupplier) { - - if (!optPreviewThumbnail.isPresent()) { + if (previewThumbnail == null) { currentSeekbarPreviewThumbnail.setVisibility(View.GONE); return; } currentSeekbarPreviewThumbnail.setVisibility(View.VISIBLE); - final Bitmap srcBitmap = optPreviewThumbnail.get(); // Resize original bitmap try { - final int srcWidth = srcBitmap.getWidth() > 0 ? srcBitmap.getWidth() : 1; + final int srcWidth = previewThumbnail.getWidth() > 0 ? previewThumbnail.getWidth() : 1; final int newWidth = MathUtils.clamp( // Use 1/4 of the width for the preview Math.round(baseViewWidthSupplier.getAsInt() / 4f), @@ -90,15 +88,16 @@ public final class SeekbarPreviewThumbnailHelper { Math.round(srcWidth * 2.5f)); final float scaleFactor = (float) newWidth / srcWidth; - final int newHeight = (int) (srcBitmap.getHeight() * scaleFactor); + final int newHeight = (int) (previewThumbnail.getHeight() * scaleFactor); - currentSeekbarPreviewThumbnail.setImageBitmap(BitmapCompat.createScaledBitmap(srcBitmap, - newWidth, newHeight, null, true)); + currentSeekbarPreviewThumbnail.setImageBitmap( + BitmapCompat.createScaledBitmap(previewThumbnail, newWidth, newHeight, null, + true)); } catch (final Exception ex) { Log.e(TAG, "Failed to resize and set seekbar preview thumbnail", ex); currentSeekbarPreviewThumbnail.setVisibility(View.GONE); } finally { - srcBitmap.recycle(); + previewThumbnail.recycle(); } } } diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java index 6226900f6..eadb1ac99 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java @@ -74,6 +74,7 @@ import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.external_communication.KoreUtils; import org.schabi.newpipe.util.external_communication.ShareUtils; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -746,15 +747,10 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh } private int getNearestStreamSegmentPosition(final long playbackPosition) { - //noinspection SimplifyOptionalCallChains - if (!player.getCurrentStreamInfo().isPresent()) { - return 0; - } - int nearestPosition = 0; final List segments = player.getCurrentStreamInfo() - .get() - .getStreamSegments(); + .map(StreamInfo::getStreamSegments) + .orElse(Collections.emptyList()); for (int i = 0; i < segments.size(); i++) { if (segments.get(i).getStartTimeSeconds() * 1000L > playbackPosition) { diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index bce75d77f..896bb4e70 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -566,7 +566,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa SeekbarPreviewThumbnailHelper .tryResizeAndSetSeekbarPreviewThumbnail( player.getContext(), - seekbarPreviewThumbnailHolder.getBitmapAt(progress), + seekbarPreviewThumbnailHolder.getBitmapAt(progress).orElse(null), binding.currentSeekbarPreviewThumbnail, binding.subtitleView::getWidth); @@ -982,61 +982,56 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa } private void updateStreamRelatedViews() { - //noinspection SimplifyOptionalCallChains - if (!player.getCurrentStreamInfo().isPresent()) { - return; - } - final StreamInfo info = player.getCurrentStreamInfo().get(); + player.getCurrentStreamInfo().ifPresent(info -> { + binding.qualityTextView.setVisibility(View.GONE); + binding.playbackSpeed.setVisibility(View.GONE); - binding.qualityTextView.setVisibility(View.GONE); - binding.playbackSpeed.setVisibility(View.GONE); + binding.playbackEndTime.setVisibility(View.GONE); + binding.playbackLiveSync.setVisibility(View.GONE); - binding.playbackEndTime.setVisibility(View.GONE); - binding.playbackLiveSync.setVisibility(View.GONE); - - switch (info.getStreamType()) { - case AUDIO_STREAM: - case POST_LIVE_AUDIO_STREAM: - binding.surfaceView.setVisibility(View.GONE); - binding.endScreen.setVisibility(View.VISIBLE); - binding.playbackEndTime.setVisibility(View.VISIBLE); - break; - - case AUDIO_LIVE_STREAM: - binding.surfaceView.setVisibility(View.GONE); - binding.endScreen.setVisibility(View.VISIBLE); - binding.playbackLiveSync.setVisibility(View.VISIBLE); - break; - - case LIVE_STREAM: - binding.surfaceView.setVisibility(View.VISIBLE); - binding.endScreen.setVisibility(View.GONE); - binding.playbackLiveSync.setVisibility(View.VISIBLE); - break; - - case VIDEO_STREAM: - case POST_LIVE_STREAM: - //noinspection SimplifyOptionalCallChains - if (player.getCurrentMetadata() != null - && !player.getCurrentMetadata().getMaybeQuality().isPresent() - || (info.getVideoStreams().isEmpty() - && info.getVideoOnlyStreams().isEmpty())) { + switch (info.getStreamType()) { + case AUDIO_STREAM: + case POST_LIVE_AUDIO_STREAM: + binding.surfaceView.setVisibility(View.GONE); + binding.endScreen.setVisibility(View.VISIBLE); + binding.playbackEndTime.setVisibility(View.VISIBLE); break; - } - buildQualityMenu(); + case AUDIO_LIVE_STREAM: + binding.surfaceView.setVisibility(View.GONE); + binding.endScreen.setVisibility(View.VISIBLE); + binding.playbackLiveSync.setVisibility(View.VISIBLE); + break; - binding.qualityTextView.setVisibility(View.VISIBLE); - binding.surfaceView.setVisibility(View.VISIBLE); - // fallthrough - default: - binding.endScreen.setVisibility(View.GONE); - binding.playbackEndTime.setVisibility(View.VISIBLE); - break; - } + case LIVE_STREAM: + binding.surfaceView.setVisibility(View.VISIBLE); + binding.endScreen.setVisibility(View.GONE); + binding.playbackLiveSync.setVisibility(View.VISIBLE); + break; - buildPlaybackSpeedMenu(); - binding.playbackSpeed.setVisibility(View.VISIBLE); + case VIDEO_STREAM: + case POST_LIVE_STREAM: + if (player.getCurrentMetadata() != null + && player.getCurrentMetadata().getMaybeQuality().isEmpty() + || (info.getVideoStreams().isEmpty() + && info.getVideoOnlyStreams().isEmpty())) { + break; + } + + buildQualityMenu(); + + binding.qualityTextView.setVisibility(View.VISIBLE); + binding.surfaceView.setVisibility(View.VISIBLE); + // fallthrough + default: + binding.endScreen.setVisibility(View.GONE); + binding.playbackEndTime.setVisibility(View.VISIBLE); + break; + } + + buildPlaybackSpeedMenu(); + binding.playbackSpeed.setVisibility(View.VISIBLE); + }); } //endregion @@ -1198,8 +1193,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa if (menuItem.getGroupId() == POPUP_MENU_ID_QUALITY) { final int menuItemIndex = menuItem.getItemId(); @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata(); - //noinspection SimplifyOptionalCallChains - if (currentMetadata == null || !currentMetadata.getMaybeQuality().isPresent()) { + if (currentMetadata == null || currentMetadata.getMaybeQuality().isEmpty()) { return true; } @@ -1300,9 +1294,8 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa // Build UI buildCaptionMenu(availableLanguages); - //noinspection SimplifyOptionalCallChains if (player.getTrackSelector().getParameters().getRendererDisabled( - player.getCaptionRendererIndex()) || !selectedTracks.isPresent()) { + player.getCaptionRendererIndex()) || selectedTracks.isEmpty()) { binding.captionTextView.setText(R.string.caption_none); } else { binding.captionTextView.setText(selectedTracks.get().language); From e3062d7c6622a665b734eaf3caaaaf37199d7a3c Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Thu, 3 Nov 2022 06:00:51 +0530 Subject: [PATCH 2/4] Use Optional chaining. --- .../fragments/detail/VideoDetailFragment.java | 13 +++---- .../org/schabi/newpipe/player/Player.java | 21 +++++------- .../player/mediaitem/MediaItemTag.java | 11 +++--- .../player/playback/MediaSourceManager.java | 34 ++++++++++--------- .../SeekbarPreviewThumbnailHelper.java | 5 ++- .../newpipe/player/ui/MainPlayerUi.java | 33 ++++++++---------- 6 files changed, 53 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index abb995ecd..d32b694d7 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -2423,23 +2423,20 @@ public final class VideoDetailFragment // helpers to check the state of player and playerService boolean isPlayerAvailable() { - return (player != null); + return player != null; } boolean isPlayerServiceAvailable() { - return (playerService != null); + return playerService != null; } boolean isPlayerAndPlayerServiceAvailable() { - return (player != null && playerService != null); + return player != null && playerService != null; } public Optional getRoot() { - if (player == null) { - return Optional.empty(); - } - - return player.UIs().get(VideoPlayerUi.class) + return Optional.ofNullable(player) + .flatMap(player1 -> player1.UIs().get(VideoPlayerUi.class)) .map(playerUi -> playerUi.getBinding().getRoot()); } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index da337b394..cc95d6be3 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1877,21 +1877,16 @@ public final class Player implements PlaybackListener, Listener { @Nullable public VideoStream getSelectedVideoStream() { - @Nullable final MediaItemTag.Quality quality = Optional.ofNullable(currentMetadata) + return Optional.ofNullable(currentMetadata) .flatMap(MediaItemTag::getMaybeQuality) + .filter(quality -> { + final int selectedStreamIndex = quality.getSelectedVideoStreamIndex(); + return selectedStreamIndex >= 0 + && selectedStreamIndex < quality.getSortedVideoStreams().size(); + }) + .map(quality -> quality.getSortedVideoStreams() + .get(quality.getSelectedVideoStreamIndex())) .orElse(null); - if (quality == null) { - return null; - } - - final List availableStreams = quality.getSortedVideoStreams(); - final int selectedStreamIndex = quality.getSelectedVideoStreamIndex(); - - if (selectedStreamIndex >= 0 && availableStreams.size() > selectedStreamIndex) { - return availableStreams.get(selectedStreamIndex); - } else { - return null; - } } //endregion diff --git a/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java b/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java index d23dd4574..f08086287 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java @@ -61,12 +61,11 @@ public interface MediaItemTag { @NonNull static Optional from(@Nullable final MediaItem mediaItem) { - if (mediaItem == null || mediaItem.localConfiguration == null - || !(mediaItem.localConfiguration.tag instanceof MediaItemTag)) { - return Optional.empty(); - } - - return Optional.of((MediaItemTag) mediaItem.localConfiguration.tag); + return Optional.ofNullable(mediaItem) + .map(item -> item.localConfiguration) + .map(localConfiguration -> localConfiguration.tag) + .filter(MediaItemTag.class::isInstance) + .map(MediaItemTag.class::cast); } @NonNull diff --git a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java index f58aa6e91..6d9fb8a1c 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java @@ -7,8 +7,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.collection.ArraySet; -import com.google.android.exoplayer2.source.MediaSource; - import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import org.schabi.newpipe.extractor.exceptions.ExtractionException; @@ -27,6 +25,7 @@ import org.schabi.newpipe.util.ServiceHelper; import java.util.Collection; import java.util.Collections; +import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -422,21 +421,24 @@ public class MediaSourceManager { private Single getLoadedMediaSource(@NonNull final PlayQueueItem stream) { return stream.getStream().map(streamInfo -> { - final MediaSource source = playbackListener.sourceOf(stream, streamInfo); - if (source == null || MediaItemTag.from(source.getMediaItem()).isEmpty()) { - final String message = "Unable to resolve source from stream info. " - + "URL: " + stream.getUrl() + ", " - + "audio count: " + streamInfo.getAudioStreams().size() + ", " - + "video count: " + streamInfo.getVideoOnlyStreams().size() + ", " - + streamInfo.getVideoStreams().size(); - return (ManagedMediaSource) - FailedMediaSource.of(stream, new MediaSourceResolutionException(message)); - } + final var source = playbackListener.sourceOf(stream, streamInfo); - final MediaItemTag tag = MediaItemTag.from(source.getMediaItem()).get(); - final long expiration = System.currentTimeMillis() - + ServiceHelper.getCacheExpirationMillis(streamInfo.getServiceId()); - return new LoadedMediaSource(source, tag, stream, expiration); + return Optional.ofNullable(source) + .flatMap(source1 -> MediaItemTag.from(source1.getMediaItem())) + .map(tag -> { + final long expiration = System.currentTimeMillis() + + ServiceHelper.getCacheExpirationMillis(streamInfo.getServiceId()); + return new LoadedMediaSource(source, tag, stream, expiration); + }) + .orElseGet(() -> { + final String message = "Unable to resolve source from stream info. " + + "URL: " + stream.getUrl() + ", " + + "audio count: " + streamInfo.getAudioStreams().size() + ", " + + "video count: " + streamInfo.getVideoOnlyStreams().size() + ", " + + streamInfo.getVideoStreams().size(); + return FailedMediaSource.of(stream, new MediaSourceResolutionException( + message)); + }); }).onErrorReturn(throwable -> { if (throwable instanceof ExtractionException) { return FailedMediaSource.of(stream, new StreamInfoLoadException(throwable)); diff --git a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java index b7441c272..28856d606 100644 --- a/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java +++ b/app/src/main/java/org/schabi/newpipe/player/seekbarpreview/SeekbarPreviewThumbnailHelper.java @@ -90,9 +90,8 @@ public final class SeekbarPreviewThumbnailHelper { final float scaleFactor = (float) newWidth / srcWidth; final int newHeight = (int) (previewThumbnail.getHeight() * scaleFactor); - currentSeekbarPreviewThumbnail.setImageBitmap( - BitmapCompat.createScaledBitmap(previewThumbnail, newWidth, newHeight, null, - true)); + currentSeekbarPreviewThumbnail.setImageBitmap(BitmapCompat + .createScaledBitmap(previewThumbnail, newWidth, newHeight, null, true)); } catch (final Exception ex) { Log.e(TAG, "Failed to resize and set seekbar preview thumbnail", ex); currentSeekbarPreviewThumbnail.setVisibility(View.GONE); diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java index eadb1ac99..683629c25 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/MainPlayerUi.java @@ -862,14 +862,11 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh @Override protected void onPlaybackSpeedClicked() { - final AppCompatActivity activity = getParentActivity().orElse(null); - if (activity == null) { - return; - } - - PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(), - player.getPlaybackSkipSilence(), player::setPlaybackParameters) - .show(activity.getSupportFragmentManager(), null); + getParentActivity().ifPresent(activity -> + PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), + player.getPlaybackPitch(), player.getPlaybackSkipSilence(), + player::setPlaybackParameters) + .show(activity.getSupportFragmentManager(), null)); } @Override @@ -969,22 +966,22 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh //////////////////////////////////////////////////////////////////////////*/ //region Getters + private Optional getParentContext() { + return Optional.ofNullable(binding.getRoot().getParent()) + .filter(ViewGroup.class::isInstance) + .map(parent -> ((ViewGroup) parent).getContext()); + } + public Optional getParentActivity() { - final ViewParent rootParent = binding.getRoot().getParent(); - if (rootParent instanceof ViewGroup) { - final Context activity = ((ViewGroup) rootParent).getContext(); - if (activity instanceof AppCompatActivity) { - return Optional.of((AppCompatActivity) activity); - } - } - return Optional.empty(); + return getParentContext() + .filter(AppCompatActivity.class::isInstance) + .map(AppCompatActivity.class::cast); } public boolean isLandscape() { // DisplayMetrics from activity context knows about MultiWindow feature // while DisplayMetrics from app context doesn't - return DeviceUtils.isLandscape( - getParentActivity().map(Context.class::cast).orElse(player.getService())); + return DeviceUtils.isLandscape(getParentContext().orElse(player.getService())); } //endregion } From e8216b2e80868f3dd3baaa91efccda39cf486cf1 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Wed, 4 Jan 2023 05:42:09 +0530 Subject: [PATCH 3/4] Apply code review suggestions. --- .../org/schabi/newpipe/player/Player.java | 1 + .../player/playback/MediaSourceManager.java | 63 ++++++++++--------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index cc95d6be3..1b60f80c9 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -2056,6 +2056,7 @@ public final class Player implements PlaybackListener, Listener { setRecovery(); }, () -> { + // This is executed when the current stream info is not available. reloadPlayQueueManager(); setRecovery(); }); diff --git a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java index 6d9fb8a1c..88d7145bc 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/playback/MediaSourceManager.java @@ -21,7 +21,6 @@ import org.schabi.newpipe.player.playqueue.events.MoveEvent; import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent; import org.schabi.newpipe.player.playqueue.events.RemoveEvent; import org.schabi.newpipe.player.playqueue.events.ReorderEvent; -import org.schabi.newpipe.util.ServiceHelper; import java.util.Collection; import java.util.Collections; @@ -42,6 +41,7 @@ import io.reactivex.rxjava3.subjects.PublishSubject; import static org.schabi.newpipe.player.mediasource.FailedMediaSource.MediaSourceResolutionException; import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfoLoadException; import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG; +import static org.schabi.newpipe.util.ServiceHelper.getCacheExpirationMillis; public class MediaSourceManager { @NonNull @@ -420,34 +420,39 @@ public class MediaSourceManager { } private Single getLoadedMediaSource(@NonNull final PlayQueueItem stream) { - return stream.getStream().map(streamInfo -> { - final var source = playbackListener.sourceOf(stream, streamInfo); - - return Optional.ofNullable(source) - .flatMap(source1 -> MediaItemTag.from(source1.getMediaItem())) - .map(tag -> { - final long expiration = System.currentTimeMillis() - + ServiceHelper.getCacheExpirationMillis(streamInfo.getServiceId()); - return new LoadedMediaSource(source, tag, stream, expiration); - }) - .orElseGet(() -> { - final String message = "Unable to resolve source from stream info. " - + "URL: " + stream.getUrl() + ", " - + "audio count: " + streamInfo.getAudioStreams().size() + ", " - + "video count: " + streamInfo.getVideoOnlyStreams().size() + ", " - + streamInfo.getVideoStreams().size(); - return FailedMediaSource.of(stream, new MediaSourceResolutionException( - message)); - }); - }).onErrorReturn(throwable -> { - if (throwable instanceof ExtractionException) { - return FailedMediaSource.of(stream, new StreamInfoLoadException(throwable)); - } - // Non-source related error expected here (e.g. network), - // should allow retry shortly after the error. - return FailedMediaSource.of(stream, new Exception(throwable), - /*allowRetryIn=*/TimeUnit.MILLISECONDS.convert(3, TimeUnit.SECONDS)); - }); + return stream.getStream() + .map(streamInfo -> Optional + .ofNullable(playbackListener.sourceOf(stream, streamInfo)) + .flatMap(source -> + MediaItemTag.from(source.getMediaItem()) + .map(tag -> { + final int serviceId = streamInfo.getServiceId(); + final long expiration = System.currentTimeMillis() + + getCacheExpirationMillis(serviceId); + return new LoadedMediaSource(source, tag, stream, + expiration); + }) + ) + .orElseGet(() -> { + final String message = "Unable to resolve source from stream info. " + + "URL: " + stream.getUrl() + + ", audio count: " + streamInfo.getAudioStreams().size() + + ", video count: " + streamInfo.getVideoOnlyStreams().size() + + ", " + streamInfo.getVideoStreams().size(); + return FailedMediaSource.of(stream, + new MediaSourceResolutionException(message)); + }) + ) + .onErrorReturn(throwable -> { + if (throwable instanceof ExtractionException) { + return FailedMediaSource.of(stream, new StreamInfoLoadException(throwable)); + } + // Non-source related error expected here (e.g. network), + // should allow retry shortly after the error. + final long allowRetryIn = TimeUnit.MILLISECONDS.convert(3, + TimeUnit.SECONDS); + return FailedMediaSource.of(stream, new Exception(throwable), allowRetryIn); + }); } private void onMediaSourceReceived(@NonNull final PlayQueueItem item, From 9c7ed80662dd8feb63ccb0cbc70852044e34fbcc Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 11 Jan 2023 14:47:53 +0100 Subject: [PATCH 4/4] Use Optional.map correctly and other improvements --- .../fragments/detail/VideoDetailFragment.java | 9 +++++--- .../org/schabi/newpipe/player/Player.java | 6 ++--- .../player/mediaitem/MediaItemTag.java | 4 ++-- .../newpipe/player/ui/VideoPlayerUi.java | 23 ++++++++----------- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index d32b694d7..1fb6b5859 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -255,7 +255,9 @@ public final class VideoDetailFragment playerUi.ifPresent(MainPlayerUi::toggleFullscreen); } - if (playAfterConnect || (currentInfo != null && isAutoplayEnabled() + if (playAfterConnect + || (currentInfo != null + && isAutoplayEnabled() && playerUi.isEmpty())) { autoPlayEnabled = true; // forcefully start playing openVideoPlayerAutoFullscreen(); @@ -1883,8 +1885,9 @@ public final class VideoDetailFragment @Override public void onFullscreenStateChanged(final boolean fullscreen) { setupBrightness(); - if (!isPlayerAndPlayerServiceAvailable() || player.UIs().get(MainPlayerUi.class).isEmpty() - || getRoot().map(View::getParent).isEmpty()) { + if (!isPlayerAndPlayerServiceAvailable() + || player.UIs().get(MainPlayerUi.class).isEmpty() + || getRoot().flatMap(v -> Optional.ofNullable(v.getParent())).isEmpty()) { return; } diff --git a/app/src/main/java/org/schabi/newpipe/player/Player.java b/app/src/main/java/org/schabi/newpipe/player/Player.java index 1b60f80c9..b6098a1ef 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1875,8 +1875,7 @@ public final class Player implements PlaybackListener, Listener { loadController.disablePreloadingOfCurrentTrack(); } - @Nullable - public VideoStream getSelectedVideoStream() { + public Optional getSelectedVideoStream() { return Optional.ofNullable(currentMetadata) .flatMap(MediaItemTag::getMaybeQuality) .filter(quality -> { @@ -1885,8 +1884,7 @@ public final class Player implements PlaybackListener, Listener { && selectedStreamIndex < quality.getSortedVideoStreams().size(); }) .map(quality -> quality.getSortedVideoStreams() - .get(quality.getSelectedVideoStreamIndex())) - .orElse(null); + .get(quality.getSelectedVideoStreamIndex())); } //endregion diff --git a/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java b/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java index f08086287..4f808caac 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediaitem/MediaItemTag.java @@ -62,8 +62,8 @@ public interface MediaItemTag { @NonNull static Optional from(@Nullable final MediaItem mediaItem) { return Optional.ofNullable(mediaItem) - .map(item -> item.localConfiguration) - .map(localConfiguration -> localConfiguration.tag) + .flatMap(item -> Optional.ofNullable(item.localConfiguration)) + .flatMap(localConfiguration -> Optional.ofNullable(localConfiguration.tag)) .filter(MediaItemTag.class::isInstance) .map(MediaItemTag.class::cast); } diff --git a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java index 896bb4e70..e4f5b05e1 100644 --- a/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java @@ -1060,12 +1060,11 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa qualityPopupMenu.getMenu().add(POPUP_MENU_ID_QUALITY, i, Menu.NONE, MediaFormat .getNameById(videoStream.getFormatId()) + " " + videoStream.getResolution()); } - final VideoStream selectedVideoStream = player.getSelectedVideoStream(); - if (selectedVideoStream != null) { - binding.qualityTextView.setText(selectedVideoStream.getResolution()); - } qualityPopupMenu.setOnMenuItemClickListener(this); qualityPopupMenu.setOnDismissListener(this); + + player.getSelectedVideoStream() + .ifPresent(s -> binding.qualityTextView.setText(s.getResolution())); } private void buildPlaybackSpeedMenu() { @@ -1171,12 +1170,9 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa qualityPopupMenu.show(); isSomePopupMenuVisible = true; - final VideoStream videoStream = player.getSelectedVideoStream(); - if (videoStream != null) { - //noinspection SetTextI18n - binding.qualityTextView.setText(MediaFormat.getNameById(videoStream.getFormatId()) - + " " + videoStream.getResolution()); - } + player.getSelectedVideoStream() + .map(s -> MediaFormat.getNameById(s.getFormatId()) + " " + s.getResolution()) + .ifPresent(binding.qualityTextView::setText); } /** @@ -1232,10 +1228,9 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa Log.d(TAG, "onDismiss() called with: menu = [" + menu + "]"); } isSomePopupMenuVisible = false; //TODO check if this works - final VideoStream selectedVideoStream = player.getSelectedVideoStream(); - if (selectedVideoStream != null) { - binding.qualityTextView.setText(selectedVideoStream.getResolution()); - } + player.getSelectedVideoStream() + .ifPresent(s -> binding.qualityTextView.setText(s.getResolution())); + if (player.isPlaying()) { hideControls(DEFAULT_CONTROLS_DURATION, 0); hideSystemUIIfNeeded();