kopia lustrzana https://github.com/TeamNewPipe/NewPipe
Merge pull request #9285 from Isira-Seneviratne/Optional_cleanup
Clean up Optional-related code.pull/9663/head
commit
87976693f8
|
@ -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);
|
||||||
|
|
Ładowanie…
Reference in New Issue