mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Merge pull request #9285 from Isira-Seneviratne/Optional_cleanup
Clean up Optional-related code.
This commit is contained in:
		| @@ -255,11 +255,10 @@ public final class VideoDetailFragment | |||||||
|             playerUi.ifPresent(MainPlayerUi::toggleFullscreen); |             playerUi.ifPresent(MainPlayerUi::toggleFullscreen); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //noinspection SimplifyOptionalCallChains |  | ||||||
|         if (playAfterConnect |         if (playAfterConnect | ||||||
|                 || (currentInfo != null |                 || (currentInfo != null | ||||||
|                 && isAutoplayEnabled() |                 && isAutoplayEnabled() | ||||||
|                 && !playerUi.isPresent())) { |                 && playerUi.isEmpty())) { | ||||||
|             autoPlayEnabled = true; // forcefully start playing |             autoPlayEnabled = true; // forcefully start playing | ||||||
|             openVideoPlayerAutoFullscreen(); |             openVideoPlayerAutoFullscreen(); | ||||||
|         } |         } | ||||||
| @@ -1174,16 +1173,15 @@ public final class VideoDetailFragment | |||||||
|      * be reused in a few milliseconds and the flickering would be annoying. |      * be reused in a few milliseconds and the flickering would be annoying. | ||||||
|      */ |      */ | ||||||
|     private void hideMainPlayerOnLoadingNewStream() { |     private void hideMainPlayerOnLoadingNewStream() { | ||||||
|         //noinspection SimplifyOptionalCallChains |         final var root = getRoot(); | ||||||
|         if (!isPlayerServiceAvailable() || !getRoot().isPresent() |         if (!isPlayerServiceAvailable() || root.isEmpty() || !player.videoPlayerSelected()) { | ||||||
|                 || !player.videoPlayerSelected()) { |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         removeVideoPlayerView(); |         removeVideoPlayerView(); | ||||||
|         if (isAutoplayEnabled()) { |         if (isAutoplayEnabled()) { | ||||||
|             playerService.stopForImmediateReusing(); |             playerService.stopForImmediateReusing(); | ||||||
|             getRoot().ifPresent(view -> view.setVisibility(View.GONE)); |             root.ifPresent(view -> view.setVisibility(View.GONE)); | ||||||
|         } else { |         } else { | ||||||
|             playerHolder.stopService(); |             playerHolder.stopService(); | ||||||
|         } |         } | ||||||
| @@ -1887,10 +1885,9 @@ public final class VideoDetailFragment | |||||||
|     @Override |     @Override | ||||||
|     public void onFullscreenStateChanged(final boolean fullscreen) { |     public void onFullscreenStateChanged(final boolean fullscreen) { | ||||||
|         setupBrightness(); |         setupBrightness(); | ||||||
|         //noinspection SimplifyOptionalCallChains |  | ||||||
|         if (!isPlayerAndPlayerServiceAvailable() |         if (!isPlayerAndPlayerServiceAvailable() | ||||||
|                 || !player.UIs().get(MainPlayerUi.class).isPresent() |                 || player.UIs().get(MainPlayerUi.class).isEmpty() | ||||||
|                 || getRoot().map(View::getParent).orElse(null) == null) { |                 || getRoot().flatMap(v -> Optional.ofNullable(v.getParent())).isEmpty()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -2429,23 +2426,20 @@ public final class VideoDetailFragment | |||||||
|  |  | ||||||
|     // helpers to check the state of player and playerService |     // helpers to check the state of player and playerService | ||||||
|     boolean isPlayerAvailable() { |     boolean isPlayerAvailable() { | ||||||
|         return (player != null); |         return player != null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     boolean isPlayerServiceAvailable() { |     boolean isPlayerServiceAvailable() { | ||||||
|         return (playerService != null); |         return playerService != null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     boolean isPlayerAndPlayerServiceAvailable() { |     boolean isPlayerAndPlayerServiceAvailable() { | ||||||
|         return (player != null && playerService != null); |         return player != null && playerService != null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public Optional<View> getRoot() { |     public Optional<View> getRoot() { | ||||||
|         if (player == null) { |         return Optional.ofNullable(player) | ||||||
|             return Optional.empty(); |                 .flatMap(player1 -> player1.UIs().get(VideoPlayerUi.class)) | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return player.UIs().get(VideoPlayerUi.class) |  | ||||||
|                 .map(playerUi -> playerUi.getBinding().getRoot()); |                 .map(playerUi -> playerUi.getBinding().getRoot()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1695,26 +1695,25 @@ public final class Player implements PlaybackListener, Listener { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void saveStreamProgressState(final long progressMillis) { |     private void saveStreamProgressState(final long progressMillis) { | ||||||
|         //noinspection SimplifyOptionalCallChains |         getCurrentStreamInfo().ifPresent(info -> { | ||||||
|         if (!getCurrentStreamInfo().isPresent() |             if (!prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)) { | ||||||
|                 || !prefs.getBoolean(context.getString(R.string.enable_watch_history_key), true)) { |                 return; | ||||||
|             return; |             } | ||||||
|         } |             if (DEBUG) { | ||||||
|         if (DEBUG) { |                 Log.d(TAG, "saveStreamProgressState() called with: progressMillis=" + progressMillis | ||||||
|             Log.d(TAG, "saveStreamProgressState() called with: progressMillis=" + progressMillis |                         + ", currentMetadata=[" + info.getName() + "]"); | ||||||
|                     + ", currentMetadata=[" + getCurrentStreamInfo().get().getName() + "]"); |             } | ||||||
|         } |  | ||||||
|  |  | ||||||
|         databaseUpdateDisposable |             databaseUpdateDisposable.add(recordManager.saveStreamState(info, progressMillis) | ||||||
|                 .add(recordManager.saveStreamState(getCurrentStreamInfo().get(), progressMillis) |                     .observeOn(AndroidSchedulers.mainThread()) | ||||||
|                 .observeOn(AndroidSchedulers.mainThread()) |                     .doOnError(e -> { | ||||||
|                 .doOnError(e -> { |                         if (DEBUG) { | ||||||
|                     if (DEBUG) { |                             e.printStackTrace(); | ||||||
|                         e.printStackTrace(); |                         } | ||||||
|                     } |                     }) | ||||||
|                 }) |                     .onErrorComplete() | ||||||
|                 .onErrorComplete() |                     .subscribe()); | ||||||
|                 .subscribe()); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void saveStreamProgressState() { |     public void saveStreamProgressState() { | ||||||
| @@ -1876,23 +1875,16 @@ public final class Player implements PlaybackListener, Listener { | |||||||
|         loadController.disablePreloadingOfCurrentTrack(); |         loadController.disablePreloadingOfCurrentTrack(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Nullable |     public Optional<VideoStream> getSelectedVideoStream() { | ||||||
|     public VideoStream getSelectedVideoStream() { |         return Optional.ofNullable(currentMetadata) | ||||||
|         @Nullable final MediaItemTag.Quality quality = Optional.ofNullable(currentMetadata) |  | ||||||
|                 .flatMap(MediaItemTag::getMaybeQuality) |                 .flatMap(MediaItemTag::getMaybeQuality) | ||||||
|                 .orElse(null); |                 .filter(quality -> { | ||||||
|         if (quality == null) { |                     final int selectedStreamIndex = quality.getSelectedVideoStreamIndex(); | ||||||
|             return null; |                     return selectedStreamIndex >= 0 | ||||||
|         } |                             && selectedStreamIndex < quality.getSortedVideoStreams().size(); | ||||||
|  |                 }) | ||||||
|         final List<VideoStream> availableStreams = quality.getSortedVideoStreams(); |                 .map(quality -> quality.getSortedVideoStreams() | ||||||
|         final int selectedStreamIndex = quality.getSelectedVideoStreamIndex(); |                         .get(quality.getSelectedVideoStreamIndex())); | ||||||
|  |  | ||||||
|         if (selectedStreamIndex >= 0 && availableStreams.size() > selectedStreamIndex) { |  | ||||||
|             return availableStreams.get(selectedStreamIndex); |  | ||||||
|         } else { |  | ||||||
|             return null; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     //endregion |     //endregion | ||||||
|  |  | ||||||
| @@ -2036,40 +2028,36 @@ public final class Player implements PlaybackListener, Listener { | |||||||
|         // in livestreams) so we will be not able to execute the block below. |         // 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 |         // 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. |         // index of the video renderer or playQueueManagerReloadingNeeded returns true. | ||||||
|         final Optional<StreamInfo> optCurrentStreamInfo = getCurrentStreamInfo(); |         getCurrentStreamInfo().ifPresentOrElse(info -> { | ||||||
|         if (!optCurrentStreamInfo.isPresent()) { |             // In the case we don't know the source type, fallback to the one with video with audio | ||||||
|             reloadPlayQueueManager(); |             // or audio-only source. | ||||||
|             setRecovery(); |             final SourceType sourceType = videoResolver.getStreamSourceType() | ||||||
|             return; |                     .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 |                 final var parametersBuilder = trackSelector.buildUponParameters(); | ||||||
|         // audio-only source. |  | ||||||
|         final SourceType sourceType = videoResolver.getStreamSourceType().orElse( |  | ||||||
|                 SourceType.VIDEO_WITH_AUDIO_OR_AUDIO_ONLY); |  | ||||||
|  |  | ||||||
|         if (playQueueManagerReloadingNeeded(sourceType, info, getVideoRendererIndex())) { |                 // Enable/disable the video track and the ability to select subtitles | ||||||
|             reloadPlayQueueManager(); |                 parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, !videoEnabled); | ||||||
|         } else { |                 parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, !videoEnabled); | ||||||
|             if (StreamTypeUtil.isAudio(info.getStreamType())) { |  | ||||||
|                 // Nothing to do more than setting the recovery position |                 trackSelector.setParameters(parametersBuilder); | ||||||
|                 setRecovery(); |  | ||||||
|                 return; |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             final DefaultTrackSelector.Parameters.Builder parametersBuilder = |             setRecovery(); | ||||||
|                     trackSelector.buildUponParameters(); |         }, () -> { | ||||||
|  |             // This is executed when the current stream info is not available. | ||||||
|             // Enable/disable the video track and the ability to select subtitles |             reloadPlayQueueManager(); | ||||||
|             parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, !videoEnabled); |             setRecovery(); | ||||||
|             parametersBuilder.setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, !videoEnabled); |         }); | ||||||
|  |  | ||||||
|             trackSelector.setParameters(parametersBuilder); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         setRecovery(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -61,12 +61,11 @@ public interface MediaItemTag { | |||||||
|  |  | ||||||
|     @NonNull |     @NonNull | ||||||
|     static Optional<MediaItemTag> from(@Nullable final MediaItem mediaItem) { |     static Optional<MediaItemTag> from(@Nullable final MediaItem mediaItem) { | ||||||
|         if (mediaItem == null || mediaItem.localConfiguration == null |         return Optional.ofNullable(mediaItem) | ||||||
|                 || !(mediaItem.localConfiguration.tag instanceof MediaItemTag)) { |                 .flatMap(item -> Optional.ofNullable(item.localConfiguration)) | ||||||
|             return Optional.empty(); |                 .flatMap(localConfiguration -> Optional.ofNullable(localConfiguration.tag)) | ||||||
|         } |                 .filter(MediaItemTag.class::isInstance) | ||||||
|  |                 .map(MediaItemTag.class::cast); | ||||||
|         return Optional.of((MediaItemTag) mediaItem.localConfiguration.tag); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @NonNull |     @NonNull | ||||||
|   | |||||||
| @@ -7,8 +7,6 @@ import androidx.annotation.NonNull; | |||||||
| import androidx.annotation.Nullable; | import androidx.annotation.Nullable; | ||||||
| import androidx.collection.ArraySet; | import androidx.collection.ArraySet; | ||||||
|  |  | ||||||
| import com.google.android.exoplayer2.source.MediaSource; |  | ||||||
|  |  | ||||||
| import org.reactivestreams.Subscriber; | import org.reactivestreams.Subscriber; | ||||||
| import org.reactivestreams.Subscription; | import org.reactivestreams.Subscription; | ||||||
| import org.schabi.newpipe.extractor.exceptions.ExtractionException; | import org.schabi.newpipe.extractor.exceptions.ExtractionException; | ||||||
| @@ -23,10 +21,10 @@ import org.schabi.newpipe.player.playqueue.events.MoveEvent; | |||||||
| import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent; | import org.schabi.newpipe.player.playqueue.events.PlayQueueEvent; | ||||||
| import org.schabi.newpipe.player.playqueue.events.RemoveEvent; | import org.schabi.newpipe.player.playqueue.events.RemoveEvent; | ||||||
| import org.schabi.newpipe.player.playqueue.events.ReorderEvent; | import org.schabi.newpipe.player.playqueue.events.ReorderEvent; | ||||||
| import org.schabi.newpipe.util.ServiceHelper; |  | ||||||
|  |  | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
|  | import java.util.Optional; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| import java.util.concurrent.atomic.AtomicBoolean; | import java.util.concurrent.atomic.AtomicBoolean; | ||||||
| @@ -43,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.MediaSourceResolutionException; | ||||||
| import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfoLoadException; | import static org.schabi.newpipe.player.mediasource.FailedMediaSource.StreamInfoLoadException; | ||||||
| import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG; | import static org.schabi.newpipe.player.playqueue.PlayQueue.DEBUG; | ||||||
|  | import static org.schabi.newpipe.util.ServiceHelper.getCacheExpirationMillis; | ||||||
|  |  | ||||||
| public class MediaSourceManager { | public class MediaSourceManager { | ||||||
|     @NonNull |     @NonNull | ||||||
| @@ -421,31 +420,39 @@ public class MediaSourceManager { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private Single<ManagedMediaSource> getLoadedMediaSource(@NonNull final PlayQueueItem stream) { |     private Single<ManagedMediaSource> getLoadedMediaSource(@NonNull final PlayQueueItem stream) { | ||||||
|         return stream.getStream().map(streamInfo -> { |         return stream.getStream() | ||||||
|             final MediaSource source = playbackListener.sourceOf(stream, streamInfo); |                 .map(streamInfo -> Optional | ||||||
|             if (source == null || !MediaItemTag.from(source.getMediaItem()).isPresent()) { |                         .ofNullable(playbackListener.sourceOf(stream, streamInfo)) | ||||||
|                 final String message = "Unable to resolve source from stream info. " |                         .<ManagedMediaSource>flatMap(source -> | ||||||
|                         + "URL: " + stream.getUrl() + ", " |                                 MediaItemTag.from(source.getMediaItem()) | ||||||
|                         + "audio count: " + streamInfo.getAudioStreams().size() + ", " |                                         .map(tag -> { | ||||||
|                         + "video count: " + streamInfo.getVideoOnlyStreams().size() + ", " |                                             final int serviceId = streamInfo.getServiceId(); | ||||||
|                         + streamInfo.getVideoStreams().size(); |                                             final long expiration = System.currentTimeMillis() | ||||||
|                 return (ManagedMediaSource) |                                                     + getCacheExpirationMillis(serviceId); | ||||||
|                         FailedMediaSource.of(stream, new MediaSourceResolutionException(message)); |                                             return new LoadedMediaSource(source, tag, stream, | ||||||
|             } |                                                     expiration); | ||||||
|  |                                         }) | ||||||
|             final MediaItemTag tag = MediaItemTag.from(source.getMediaItem()).get(); |                         ) | ||||||
|             final long expiration = System.currentTimeMillis() |                         .orElseGet(() -> { | ||||||
|                     + ServiceHelper.getCacheExpirationMillis(streamInfo.getServiceId()); |                             final String message = "Unable to resolve source from stream info. " | ||||||
|             return new LoadedMediaSource(source, tag, stream, expiration); |                                     + "URL: " + stream.getUrl() | ||||||
|         }).onErrorReturn(throwable -> { |                                     + ", audio count: " + streamInfo.getAudioStreams().size() | ||||||
|             if (throwable instanceof ExtractionException) { |                                     + ", video count: " + streamInfo.getVideoOnlyStreams().size() | ||||||
|                 return FailedMediaSource.of(stream, new StreamInfoLoadException(throwable)); |                                     + ", " + streamInfo.getVideoStreams().size(); | ||||||
|             } |                             return FailedMediaSource.of(stream, | ||||||
|             // Non-source related error expected here (e.g. network), |                                     new MediaSourceResolutionException(message)); | ||||||
|             // should allow retry shortly after the error. |                         }) | ||||||
|             return FailedMediaSource.of(stream, new Exception(throwable), |                 ) | ||||||
|                     /*allowRetryIn=*/TimeUnit.MILLISECONDS.convert(3, TimeUnit.SECONDS)); |                 .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, |     private void onMediaSourceReceived(@NonNull final PlayQueueItem item, | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import android.widget.ImageView; | |||||||
|  |  | ||||||
| import androidx.annotation.IntDef; | import androidx.annotation.IntDef; | ||||||
| import androidx.annotation.NonNull; | import androidx.annotation.NonNull; | ||||||
|  | import androidx.annotation.Nullable; | ||||||
| import androidx.core.graphics.BitmapCompat; | import androidx.core.graphics.BitmapCompat; | ||||||
| import androidx.core.math.MathUtils; | import androidx.core.math.MathUtils; | ||||||
| import androidx.preference.PreferenceManager; | import androidx.preference.PreferenceManager; | ||||||
| @@ -16,7 +17,6 @@ import org.schabi.newpipe.R; | |||||||
| import org.schabi.newpipe.util.DeviceUtils; | import org.schabi.newpipe.util.DeviceUtils; | ||||||
|  |  | ||||||
| import java.lang.annotation.Retention; | import java.lang.annotation.Retention; | ||||||
| import java.util.Optional; |  | ||||||
| import java.util.function.IntSupplier; | import java.util.function.IntSupplier; | ||||||
|  |  | ||||||
| import static java.lang.annotation.RetentionPolicy.SOURCE; | import static java.lang.annotation.RetentionPolicy.SOURCE; | ||||||
| @@ -66,21 +66,19 @@ public final class SeekbarPreviewThumbnailHelper { | |||||||
|  |  | ||||||
|     public static void tryResizeAndSetSeekbarPreviewThumbnail( |     public static void tryResizeAndSetSeekbarPreviewThumbnail( | ||||||
|             @NonNull final Context context, |             @NonNull final Context context, | ||||||
|             @NonNull final Optional<Bitmap> optPreviewThumbnail, |             @Nullable final Bitmap previewThumbnail, | ||||||
|             @NonNull final ImageView currentSeekbarPreviewThumbnail, |             @NonNull final ImageView currentSeekbarPreviewThumbnail, | ||||||
|             @NonNull final IntSupplier baseViewWidthSupplier) { |             @NonNull final IntSupplier baseViewWidthSupplier) { | ||||||
|  |         if (previewThumbnail == null) { | ||||||
|         if (!optPreviewThumbnail.isPresent()) { |  | ||||||
|             currentSeekbarPreviewThumbnail.setVisibility(View.GONE); |             currentSeekbarPreviewThumbnail.setVisibility(View.GONE); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         currentSeekbarPreviewThumbnail.setVisibility(View.VISIBLE); |         currentSeekbarPreviewThumbnail.setVisibility(View.VISIBLE); | ||||||
|         final Bitmap srcBitmap = optPreviewThumbnail.get(); |  | ||||||
|  |  | ||||||
|         // Resize original bitmap |         // Resize original bitmap | ||||||
|         try { |         try { | ||||||
|             final int srcWidth = srcBitmap.getWidth() > 0 ? srcBitmap.getWidth() : 1; |             final int srcWidth = previewThumbnail.getWidth() > 0 ? previewThumbnail.getWidth() : 1; | ||||||
|             final int newWidth = MathUtils.clamp( |             final int newWidth = MathUtils.clamp( | ||||||
|                     // Use 1/4 of the width for the preview |                     // Use 1/4 of the width for the preview | ||||||
|                     Math.round(baseViewWidthSupplier.getAsInt() / 4f), |                     Math.round(baseViewWidthSupplier.getAsInt() / 4f), | ||||||
| @@ -90,15 +88,15 @@ public final class SeekbarPreviewThumbnailHelper { | |||||||
|                     Math.round(srcWidth * 2.5f)); |                     Math.round(srcWidth * 2.5f)); | ||||||
|  |  | ||||||
|             final float scaleFactor = (float) newWidth / srcWidth; |             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, |             currentSeekbarPreviewThumbnail.setImageBitmap(BitmapCompat | ||||||
|                     newWidth, newHeight, null, true)); |                     .createScaledBitmap(previewThumbnail, newWidth, newHeight, null, true)); | ||||||
|         } catch (final Exception ex) { |         } catch (final Exception ex) { | ||||||
|             Log.e(TAG, "Failed to resize and set seekbar preview thumbnail", ex); |             Log.e(TAG, "Failed to resize and set seekbar preview thumbnail", ex); | ||||||
|             currentSeekbarPreviewThumbnail.setVisibility(View.GONE); |             currentSeekbarPreviewThumbnail.setVisibility(View.GONE); | ||||||
|         } finally { |         } finally { | ||||||
|             srcBitmap.recycle(); |             previewThumbnail.recycle(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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.KoreUtils; | ||||||
| import org.schabi.newpipe.util.external_communication.ShareUtils; | import org.schabi.newpipe.util.external_communication.ShareUtils; | ||||||
|  |  | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.Optional; | import java.util.Optional; | ||||||
| @@ -746,15 +747,10 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private int getNearestStreamSegmentPosition(final long playbackPosition) { |     private int getNearestStreamSegmentPosition(final long playbackPosition) { | ||||||
|         //noinspection SimplifyOptionalCallChains |  | ||||||
|         if (!player.getCurrentStreamInfo().isPresent()) { |  | ||||||
|             return 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         int nearestPosition = 0; |         int nearestPosition = 0; | ||||||
|         final List<StreamSegment> segments = player.getCurrentStreamInfo() |         final List<StreamSegment> segments = player.getCurrentStreamInfo() | ||||||
|                 .get() |                 .map(StreamInfo::getStreamSegments) | ||||||
|                 .getStreamSegments(); |                 .orElse(Collections.emptyList()); | ||||||
|  |  | ||||||
|         for (int i = 0; i < segments.size(); i++) { |         for (int i = 0; i < segments.size(); i++) { | ||||||
|             if (segments.get(i).getStartTimeSeconds() * 1000L > playbackPosition) { |             if (segments.get(i).getStartTimeSeconds() * 1000L > playbackPosition) { | ||||||
| @@ -866,14 +862,11 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     protected void onPlaybackSpeedClicked() { |     protected void onPlaybackSpeedClicked() { | ||||||
|         final AppCompatActivity activity = getParentActivity().orElse(null); |         getParentActivity().ifPresent(activity -> | ||||||
|         if (activity == null) { |                 PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), | ||||||
|             return; |                                 player.getPlaybackPitch(), player.getPlaybackSkipSilence(), | ||||||
|         } |                                 player::setPlaybackParameters) | ||||||
|  |                         .show(activity.getSupportFragmentManager(), null)); | ||||||
|         PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(), |  | ||||||
|                 player.getPlaybackSkipSilence(), player::setPlaybackParameters) |  | ||||||
|                 .show(activity.getSupportFragmentManager(), null); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -973,22 +966,22 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh | |||||||
|     //////////////////////////////////////////////////////////////////////////*/ |     //////////////////////////////////////////////////////////////////////////*/ | ||||||
|     //region Getters |     //region Getters | ||||||
|  |  | ||||||
|  |     private Optional<Context> getParentContext() { | ||||||
|  |         return Optional.ofNullable(binding.getRoot().getParent()) | ||||||
|  |                 .filter(ViewGroup.class::isInstance) | ||||||
|  |                 .map(parent -> ((ViewGroup) parent).getContext()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public Optional<AppCompatActivity> getParentActivity() { |     public Optional<AppCompatActivity> getParentActivity() { | ||||||
|         final ViewParent rootParent = binding.getRoot().getParent(); |         return getParentContext() | ||||||
|         if (rootParent instanceof ViewGroup) { |                 .filter(AppCompatActivity.class::isInstance) | ||||||
|             final Context activity = ((ViewGroup) rootParent).getContext(); |                 .map(AppCompatActivity.class::cast); | ||||||
|             if (activity instanceof AppCompatActivity) { |  | ||||||
|                 return Optional.of((AppCompatActivity) activity); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return Optional.empty(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public boolean isLandscape() { |     public boolean isLandscape() { | ||||||
|         // DisplayMetrics from activity context knows about MultiWindow feature |         // DisplayMetrics from activity context knows about MultiWindow feature | ||||||
|         // while DisplayMetrics from app context doesn't |         // while DisplayMetrics from app context doesn't | ||||||
|         return DeviceUtils.isLandscape( |         return DeviceUtils.isLandscape(getParentContext().orElse(player.getService())); | ||||||
|                 getParentActivity().map(Context.class::cast).orElse(player.getService())); |  | ||||||
|     } |     } | ||||||
|     //endregion |     //endregion | ||||||
| } | } | ||||||
|   | |||||||
| @@ -566,7 +566,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|         SeekbarPreviewThumbnailHelper |         SeekbarPreviewThumbnailHelper | ||||||
|                 .tryResizeAndSetSeekbarPreviewThumbnail( |                 .tryResizeAndSetSeekbarPreviewThumbnail( | ||||||
|                         player.getContext(), |                         player.getContext(), | ||||||
|                         seekbarPreviewThumbnailHolder.getBitmapAt(progress), |                         seekbarPreviewThumbnailHolder.getBitmapAt(progress).orElse(null), | ||||||
|                         binding.currentSeekbarPreviewThumbnail, |                         binding.currentSeekbarPreviewThumbnail, | ||||||
|                         binding.subtitleView::getWidth); |                         binding.subtitleView::getWidth); | ||||||
|  |  | ||||||
| @@ -982,61 +982,56 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void updateStreamRelatedViews() { |     private void updateStreamRelatedViews() { | ||||||
|         //noinspection SimplifyOptionalCallChains |         player.getCurrentStreamInfo().ifPresent(info -> { | ||||||
|         if (!player.getCurrentStreamInfo().isPresent()) { |             binding.qualityTextView.setVisibility(View.GONE); | ||||||
|             return; |             binding.playbackSpeed.setVisibility(View.GONE); | ||||||
|         } |  | ||||||
|         final StreamInfo info = player.getCurrentStreamInfo().get(); |  | ||||||
|  |  | ||||||
|         binding.qualityTextView.setVisibility(View.GONE); |             binding.playbackEndTime.setVisibility(View.GONE); | ||||||
|         binding.playbackSpeed.setVisibility(View.GONE); |             binding.playbackLiveSync.setVisibility(View.GONE); | ||||||
|  |  | ||||||
|         binding.playbackEndTime.setVisibility(View.GONE); |             switch (info.getStreamType()) { | ||||||
|         binding.playbackLiveSync.setVisibility(View.GONE); |                 case AUDIO_STREAM: | ||||||
|  |                 case POST_LIVE_AUDIO_STREAM: | ||||||
|         switch (info.getStreamType()) { |                     binding.surfaceView.setVisibility(View.GONE); | ||||||
|             case AUDIO_STREAM: |                     binding.endScreen.setVisibility(View.VISIBLE); | ||||||
|             case POST_LIVE_AUDIO_STREAM: |                     binding.playbackEndTime.setVisibility(View.VISIBLE); | ||||||
|                 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())) { |  | ||||||
|                     break; |                     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); |                 case LIVE_STREAM: | ||||||
|                 binding.surfaceView.setVisibility(View.VISIBLE); |                     binding.surfaceView.setVisibility(View.VISIBLE); | ||||||
|                 // fallthrough |                     binding.endScreen.setVisibility(View.GONE); | ||||||
|             default: |                     binding.playbackLiveSync.setVisibility(View.VISIBLE); | ||||||
|                 binding.endScreen.setVisibility(View.GONE); |                     break; | ||||||
|                 binding.playbackEndTime.setVisibility(View.VISIBLE); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         buildPlaybackSpeedMenu(); |                 case VIDEO_STREAM: | ||||||
|         binding.playbackSpeed.setVisibility(View.VISIBLE); |                 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 |     //endregion | ||||||
|  |  | ||||||
| @@ -1065,12 +1060,11 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|             qualityPopupMenu.getMenu().add(POPUP_MENU_ID_QUALITY, i, Menu.NONE, MediaFormat |             qualityPopupMenu.getMenu().add(POPUP_MENU_ID_QUALITY, i, Menu.NONE, MediaFormat | ||||||
|                     .getNameById(videoStream.getFormatId()) + " " + videoStream.getResolution()); |                     .getNameById(videoStream.getFormatId()) + " " + videoStream.getResolution()); | ||||||
|         } |         } | ||||||
|         final VideoStream selectedVideoStream = player.getSelectedVideoStream(); |  | ||||||
|         if (selectedVideoStream != null) { |  | ||||||
|             binding.qualityTextView.setText(selectedVideoStream.getResolution()); |  | ||||||
|         } |  | ||||||
|         qualityPopupMenu.setOnMenuItemClickListener(this); |         qualityPopupMenu.setOnMenuItemClickListener(this); | ||||||
|         qualityPopupMenu.setOnDismissListener(this); |         qualityPopupMenu.setOnDismissListener(this); | ||||||
|  |  | ||||||
|  |         player.getSelectedVideoStream() | ||||||
|  |                 .ifPresent(s -> binding.qualityTextView.setText(s.getResolution())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void buildPlaybackSpeedMenu() { |     private void buildPlaybackSpeedMenu() { | ||||||
| @@ -1176,12 +1170,9 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|         qualityPopupMenu.show(); |         qualityPopupMenu.show(); | ||||||
|         isSomePopupMenuVisible = true; |         isSomePopupMenuVisible = true; | ||||||
|  |  | ||||||
|         final VideoStream videoStream = player.getSelectedVideoStream(); |         player.getSelectedVideoStream() | ||||||
|         if (videoStream != null) { |                 .map(s -> MediaFormat.getNameById(s.getFormatId()) + " " + s.getResolution()) | ||||||
|             //noinspection SetTextI18n |                 .ifPresent(binding.qualityTextView::setText); | ||||||
|             binding.qualityTextView.setText(MediaFormat.getNameById(videoStream.getFormatId()) |  | ||||||
|                     + " " + videoStream.getResolution()); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -1198,8 +1189,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|         if (menuItem.getGroupId() == POPUP_MENU_ID_QUALITY) { |         if (menuItem.getGroupId() == POPUP_MENU_ID_QUALITY) { | ||||||
|             final int menuItemIndex = menuItem.getItemId(); |             final int menuItemIndex = menuItem.getItemId(); | ||||||
|             @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata(); |             @Nullable final MediaItemTag currentMetadata = player.getCurrentMetadata(); | ||||||
|             //noinspection SimplifyOptionalCallChains |             if (currentMetadata == null || currentMetadata.getMaybeQuality().isEmpty()) { | ||||||
|             if (currentMetadata == null || !currentMetadata.getMaybeQuality().isPresent()) { |  | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -1238,10 +1228,9 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|             Log.d(TAG, "onDismiss() called with: menu = [" + menu + "]"); |             Log.d(TAG, "onDismiss() called with: menu = [" + menu + "]"); | ||||||
|         } |         } | ||||||
|         isSomePopupMenuVisible = false; //TODO check if this works |         isSomePopupMenuVisible = false; //TODO check if this works | ||||||
|         final VideoStream selectedVideoStream = player.getSelectedVideoStream(); |         player.getSelectedVideoStream() | ||||||
|         if (selectedVideoStream != null) { |                 .ifPresent(s -> binding.qualityTextView.setText(s.getResolution())); | ||||||
|             binding.qualityTextView.setText(selectedVideoStream.getResolution()); |  | ||||||
|         } |  | ||||||
|         if (player.isPlaying()) { |         if (player.isPlaying()) { | ||||||
|             hideControls(DEFAULT_CONTROLS_DURATION, 0); |             hideControls(DEFAULT_CONTROLS_DURATION, 0); | ||||||
|             hideSystemUIIfNeeded(); |             hideSystemUIIfNeeded(); | ||||||
| @@ -1300,9 +1289,8 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa | |||||||
|  |  | ||||||
|         // Build UI |         // Build UI | ||||||
|         buildCaptionMenu(availableLanguages); |         buildCaptionMenu(availableLanguages); | ||||||
|         //noinspection SimplifyOptionalCallChains |  | ||||||
|         if (player.getTrackSelector().getParameters().getRendererDisabled( |         if (player.getTrackSelector().getParameters().getRendererDisabled( | ||||||
|                 player.getCaptionRendererIndex()) || !selectedTracks.isPresent()) { |                 player.getCaptionRendererIndex()) || selectedTracks.isEmpty()) { | ||||||
|             binding.captionTextView.setText(R.string.caption_none); |             binding.captionTextView.setText(R.string.caption_none); | ||||||
|         } else { |         } else { | ||||||
|             binding.captionTextView.setText(selectedTracks.get().language); |             binding.captionTextView.setText(selectedTracks.get().language); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Stypox
					Stypox