From b2e2551e33603dcb7f7c1220bd59dda507802e54 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 24 Sep 2021 15:00:37 +0200 Subject: [PATCH 1/5] Two fixes for setMetadata --- .../org/schabi/newpipe/player/Player.java | 16 ++++++--- .../player/helper/MediaSessionManager.java | 33 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 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 5ad855e787f..72a69962350 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1626,8 +1626,12 @@ private void onUpdateProgress(final int currentProgress, final boolean showThumbnail = prefs.getBoolean( context.getString(R.string.show_thumbnail_key), true); // setMetadata only updates the metadata when any of the metadata keys are null - mediaSessionManager.setMetadata(getVideoTitle(), getUploaderName(), - showThumbnail ? getThumbnail() : null, duration); + if (showThumbnail) { + mediaSessionManager.setMetadata(getVideoTitle(), getUploaderName(), getThumbnail(), + duration); + } else { + mediaSessionManager.setMetadata(getVideoTitle(), getUploaderName(), duration); + } } private void startProgressLoop() { @@ -3023,9 +3027,11 @@ public String getUploaderName() { @Nullable public Bitmap getThumbnail() { - return currentThumbnail == null - ? BitmapFactory.decodeResource(context.getResources(), R.drawable.dummy_thumbnail) - : currentThumbnail; + if (currentThumbnail == null) { + currentThumbnail = BitmapFactory.decodeResource( + context.getResources(), R.drawable.dummy_thumbnail); + } + return currentThumbnail; } //endregion diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index c7f1f9c8c84..5bab1cb9a74 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -65,6 +65,39 @@ public MediaSessionCompat.Token getSessionToken() { return mediaSession.getSessionToken(); } + public void setMetadata(final String title, + final String artist, + final long duration) { + if (!mediaSession.isActive()) { + return; + } + + if (DEBUG) { + if (getMetadataTitle() == null) { + Log.d(TAG, "N_getMetadataTitle: title == null"); + } + if (getMetadataArtist() == null) { + Log.d(TAG, "N_getMetadataArtist: artist == null"); + } + if (getMetadataDuration() <= 1) { + Log.d(TAG, "N_getMetadataDuration: duration <= 1; " + getMetadataDuration()); + } + } + + if (getMetadataTitle() == null || getMetadataArtist() == null || getMetadataDuration() <= 1 + || !getMetadataTitle().equals(title)) { + if (DEBUG) { + Log.d(TAG, "setMetadata: N_Metadata update: t: " + title + " a: " + artist + + " d: " + duration); + } + + mediaSession.setMetadata(new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration).build()); + } + } + public void setMetadata(final String title, final String artist, final Bitmap albumArt, From c0d41661e85b512079a0a6cb1ceb5d254631d42d Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Fri, 24 Sep 2021 23:40:12 +0200 Subject: [PATCH 2/5] Fixed performance problems with mediaSessionManager * Built on top of Redirons changes * MediaSessionManager-Metadata get's only update when metadata changes - not every second as it only changes when the metadata changes * Reworked mediasessionmanager --- .../org/schabi/newpipe/player/Player.java | 21 +-- .../player/helper/MediaSessionManager.java | 143 +++++++++++------- 2 files changed, 102 insertions(+), 62 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 72a69962350..7e21a58ebf0 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -140,6 +140,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.core.Observable; @@ -1622,16 +1623,6 @@ private void onUpdateProgress(final int currentProgress, if (isQueueVisible) { updateQueueTime(currentProgress); } - - final boolean showThumbnail = prefs.getBoolean( - context.getString(R.string.show_thumbnail_key), true); - // setMetadata only updates the metadata when any of the metadata keys are null - if (showThumbnail) { - mediaSessionManager.setMetadata(getVideoTitle(), getUploaderName(), getThumbnail(), - duration); - } else { - mediaSessionManager.setMetadata(getVideoTitle(), getUploaderName(), duration); - } } private void startProgressLoop() { @@ -2950,6 +2941,16 @@ private void onMetadataChanged(@NonNull final MediaSourceTag tag) { tag.getMetadata().getPreviewFrames()); NotificationUtil.getInstance().createNotificationIfNeededAndUpdate(this, false); + + final boolean showThumbnail = prefs.getBoolean( + context.getString(R.string.show_thumbnail_key), true); + mediaSessionManager.setMetadata( + getVideoTitle(), + getUploaderName(), + showThumbnail ? Optional.ofNullable(getThumbnail()) : Optional.empty(), + tag.getMetadata().getDuration() + ); + notifyMetadataUpdateToListeners(); if (areSegmentsVisible) { diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index 5bab1cb9a74..938a3aade7a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -21,6 +21,8 @@ import org.schabi.newpipe.player.mediasession.PlayQueueNavigator; import org.schabi.newpipe.player.mediasession.PlayQueuePlaybackController; +import java.util.Optional; + public class MediaSessionManager { private static final String TAG = MediaSessionManager.class.getSimpleName(); public static final boolean DEBUG = MainActivity.DEBUG; @@ -30,6 +32,9 @@ public class MediaSessionManager { @NonNull private final MediaSessionConnector sessionConnector; + private int lastTitleHashCode; + private int lastArtistHashCode; + private long lastDuration; private int lastAlbumArtHashCode; public MediaSessionManager(@NonNull final Context context, @@ -65,80 +70,114 @@ public MediaSessionCompat.Token getSessionToken() { return mediaSession.getSessionToken(); } - public void setMetadata(final String title, - final String artist, - final long duration) { - if (!mediaSession.isActive()) { - return; + public void setMetadata(@NonNull final String title, + @NonNull final String artist, + @NonNull final Optional optAlbumArt, + final long duration + ) { + if (DEBUG) { + Log.d(TAG, "setMetadata called:" + + " t: " + title + + " a: " + artist + + " thumb: " + ( + optAlbumArt.isPresent() + ? optAlbumArt.get().hashCode() + : "") + + " d: " + duration); } - if (DEBUG) { - if (getMetadataTitle() == null) { - Log.d(TAG, "N_getMetadataTitle: title == null"); - } - if (getMetadataArtist() == null) { - Log.d(TAG, "N_getMetadataArtist: artist == null"); - } - if (getMetadataDuration() <= 1) { - Log.d(TAG, "N_getMetadataDuration: duration <= 1; " + getMetadataDuration()); + if (!mediaSession.isActive()) { + if (DEBUG) { + Log.d(TAG, "setMetadata: mediaSession not active - exiting"); } + return; } - if (getMetadataTitle() == null || getMetadataArtist() == null || getMetadataDuration() <= 1 - || !getMetadataTitle().equals(title)) { + if (checkIfMetadataShouldBeSet(title, artist, optAlbumArt, duration)) { if (DEBUG) { - Log.d(TAG, "setMetadata: N_Metadata update: t: " + title + " a: " + artist + Log.d(TAG, "setMetadata: N_Metadata update:" + + " t: " + title + + " a: " + artist + + " thumb: " + ( + optAlbumArt.isPresent() + ? optAlbumArt.get().hashCode() + : "") + " d: " + duration); } - mediaSession.setMetadata(new MediaMetadataCompat.Builder() + final MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) - .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration).build()); - } - } - - public void setMetadata(final String title, - final String artist, - final Bitmap albumArt, - final long duration) { - if (albumArt == null || !mediaSession.isActive()) { - return; - } + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration); - if (DEBUG) { - if (getMetadataAlbumArt() == null) { - Log.d(TAG, "N_getMetadataAlbumArt: thumb == null"); + if (optAlbumArt.isPresent()) { + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, optAlbumArt.get()); + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, optAlbumArt.get()); } - if (getMetadataTitle() == null) { - Log.d(TAG, "N_getMetadataTitle: title == null"); + + mediaSession.setMetadata(builder.build()); + + lastTitleHashCode = title.hashCode(); + lastArtistHashCode = artist.hashCode(); + lastDuration = duration; + if (optAlbumArt.isPresent()) { + lastAlbumArtHashCode = optAlbumArt.get().hashCode(); } - if (getMetadataArtist() == null) { - Log.d(TAG, "N_getMetadataArtist: artist == null"); + } + } + + private boolean checkIfMetadataShouldBeSet( + @NonNull final String title, + @NonNull final String artist, + @NonNull final Optional optAlbumArt, + final long duration + ) { + // Check if the values have changed since the last time + if (title.hashCode() != lastTitleHashCode + || artist.hashCode() != lastArtistHashCode + || duration != lastDuration + || (optAlbumArt.isPresent() && optAlbumArt.get().hashCode() != lastAlbumArtHashCode) + ) { + if (DEBUG) { + Log.d(TAG, + "checkIfMetadataShouldBeSet: true - reason: changed values since last"); } - if (getMetadataDuration() <= 1) { - Log.d(TAG, "N_getMetadataDuration: duration <= 1; " + getMetadataDuration()); + return true; + } + // Check if the current metadata is valid + if (getMetadataTitle() == null + || getMetadataArtist() == null + || getMetadataDuration() <= 1 + ) { + if (DEBUG) { + if (getMetadataTitle() == null) { + Log.d(TAG, + "N_getMetadataTitle: title == null"); + } else if (getMetadataArtist() == null) { + Log.d(TAG, + "N_getMetadataArtist: artist == null"); + } else if (getMetadataDuration() <= 1) { + Log.d(TAG, + "N_getMetadataDuration: duration <= 1; " + getMetadataDuration()); + } } + return true; } - - if (getMetadataAlbumArt() == null || getMetadataTitle() == null - || getMetadataArtist() == null || getMetadataDuration() <= 1 - || albumArt.hashCode() != lastAlbumArtHashCode) { + // If we got an album art check if the current set AlbumArt is null + if (optAlbumArt.isPresent() && getMetadataAlbumArt() == null) { if (DEBUG) { - Log.d(TAG, "setMetadata: N_Metadata update: t: " + title + " a: " + artist - + " thumb: " + albumArt.hashCode() + " d: " + duration); + if (getMetadataAlbumArt() == null) { + Log.d(TAG, "N_getMetadataAlbumArt: thumb == null"); + } } - - mediaSession.setMetadata(new MediaMetadataCompat.Builder() - .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) - .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) - .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt) - .putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, albumArt) - .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration).build()); - lastAlbumArtHashCode = albumArt.hashCode(); + return true; } + + // Default - no update required + return false; } + private Bitmap getMetadataAlbumArt() { return mediaSession.getController().getMetadata() .getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART); From ba0876b43b7527ca40e99685156db6cedebc1311 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Fri, 24 Sep 2021 23:55:06 +0200 Subject: [PATCH 3/5] Reformatted MediaSessionManager code --- .../player/helper/MediaSessionManager.java | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index 938a3aade7a..dcc8c0d2172 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -93,36 +93,41 @@ public void setMetadata(@NonNull final String title, return; } - if (checkIfMetadataShouldBeSet(title, artist, optAlbumArt, duration)) { + if (!checkIfMetadataShouldBeSet(title, artist, optAlbumArt, duration)) { if (DEBUG) { - Log.d(TAG, "setMetadata: N_Metadata update:" - + " t: " + title - + " a: " + artist - + " thumb: " + ( - optAlbumArt.isPresent() - ? optAlbumArt.get().hashCode() - : "") - + " d: " + duration); + Log.d(TAG, "setMetadata: No update required"); } + return; + } - final MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder() - .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) - .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) - .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration); + if (DEBUG) { + Log.d(TAG, "setMetadata: N_Metadata update:" + + " t: " + title + + " a: " + artist + + " thumb: " + ( + optAlbumArt.isPresent() + ? optAlbumArt.get().hashCode() + : "") + + " d: " + duration); + } - if (optAlbumArt.isPresent()) { - builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, optAlbumArt.get()); - builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, optAlbumArt.get()); - } + final MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration); + + if (optAlbumArt.isPresent()) { + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, optAlbumArt.get()); + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, optAlbumArt.get()); + } - mediaSession.setMetadata(builder.build()); + mediaSession.setMetadata(builder.build()); - lastTitleHashCode = title.hashCode(); - lastArtistHashCode = artist.hashCode(); - lastDuration = duration; - if (optAlbumArt.isPresent()) { - lastAlbumArtHashCode = optAlbumArt.get().hashCode(); - } + lastTitleHashCode = title.hashCode(); + lastArtistHashCode = artist.hashCode(); + lastDuration = duration; + if (optAlbumArt.isPresent()) { + lastAlbumArtHashCode = optAlbumArt.get().hashCode(); } } @@ -144,6 +149,7 @@ private boolean checkIfMetadataShouldBeSet( } return true; } + // Check if the current metadata is valid if (getMetadataTitle() == null || getMetadataArtist() == null @@ -163,6 +169,7 @@ private boolean checkIfMetadataShouldBeSet( } return true; } + // If we got an album art check if the current set AlbumArt is null if (optAlbumArt.isPresent() && getMetadataAlbumArt() == null) { if (DEBUG) { From bbc13756f3653a5624b47f55f4654320ebee5a57 Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 25 Sep 2021 00:04:53 +0200 Subject: [PATCH 4/5] Removed useless check for livestreams --- .../newpipe/player/helper/MediaSessionManager.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index dcc8c0d2172..da478952ccb 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -150,10 +150,10 @@ private boolean checkIfMetadataShouldBeSet( return true; } - // Check if the current metadata is valid + // Check if the currently set metadata is valid if (getMetadataTitle() == null || getMetadataArtist() == null - || getMetadataDuration() <= 1 + // Note that the duration can be <= 0 for live streams ) { if (DEBUG) { if (getMetadataTitle() == null) { @@ -162,9 +162,6 @@ private boolean checkIfMetadataShouldBeSet( } else if (getMetadataArtist() == null) { Log.d(TAG, "N_getMetadataArtist: artist == null"); - } else if (getMetadataDuration() <= 1) { - Log.d(TAG, - "N_getMetadataDuration: duration <= 1; " + getMetadataDuration()); } } return true; @@ -200,11 +197,6 @@ private String getMetadataArtist() { .getString(MediaMetadataCompat.METADATA_KEY_ARTIST); } - private long getMetadataDuration() { - return mediaSession.getController().getMetadata() - .getLong(MediaMetadataCompat.METADATA_KEY_DURATION); - } - /** * Should be called on player destruction to prevent leakage. */ From 72dbb9441e9d1b8e9d00c81825d5b69b7658082a Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sat, 25 Sep 2021 10:31:42 +0200 Subject: [PATCH 5/5] Improved streamType check and documentation --- .../newpipe/local/feed/item/StreamItem.kt | 5 +- .../org/schabi/newpipe/player/Player.java | 110 +++++++++--------- .../player/helper/MediaSessionManager.java | 11 +- .../player/resolver/PlaybackResolver.java | 3 +- .../schabi/newpipe/util/StreamTypeUtil.java | 24 ++++ 5 files changed, 94 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/util/StreamTypeUtil.java diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt b/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt index c454f7eec22..0d2caf126d8 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/item/StreamItem.kt @@ -17,6 +17,7 @@ import org.schabi.newpipe.extractor.stream.StreamType.LIVE_STREAM import org.schabi.newpipe.extractor.stream.StreamType.VIDEO_STREAM import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.PicassoHelper +import org.schabi.newpipe.util.StreamTypeUtil import java.util.concurrent.TimeUnit data class StreamItem( @@ -58,8 +59,6 @@ data class StreamItem( viewBinding.itemVideoTitleView.text = stream.title viewBinding.itemUploaderView.text = stream.uploader - val isLiveStream = stream.streamType == LIVE_STREAM || stream.streamType == AUDIO_LIVE_STREAM - if (stream.duration > 0) { viewBinding.itemDurationView.text = Localization.getDurationString(stream.duration) viewBinding.itemDurationView.setBackgroundColor( @@ -77,7 +76,7 @@ data class StreamItem( } else { viewBinding.itemProgressView.visibility = View.GONE } - } else if (isLiveStream) { + } else if (StreamTypeUtil.isLiveStream(stream.streamType)) { viewBinding.itemDurationView.setText(R.string.duration_live) viewBinding.itemDurationView.setBackgroundColor( ContextCompat.getColor( 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 7e21a58ebf0..05e2bed786e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/Player.java +++ b/app/src/main/java/org/schabi/newpipe/player/Player.java @@ -1,5 +1,53 @@ package org.schabi.newpipe.player; +import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_AD_INSERTION; +import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL; +import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION; +import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK; +import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT; +import static com.google.android.exoplayer2.Player.DiscontinuityReason; +import static com.google.android.exoplayer2.Player.EventListener; +import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL; +import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF; +import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE; +import static com.google.android.exoplayer2.Player.RepeatMode; +import static org.schabi.newpipe.QueueItemMenuUtil.openPopupMenu; +import static org.schabi.newpipe.extractor.ServiceList.YouTube; +import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; +import static org.schabi.newpipe.ktx.ViewUtils.animate; +import static org.schabi.newpipe.ktx.ViewUtils.animateRotation; +import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE; +import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD; +import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND; +import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT; +import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PAUSE; +import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS; +import static org.schabi.newpipe.player.MainPlayer.ACTION_RECREATE_NOTIFICATION; +import static org.schabi.newpipe.player.MainPlayer.ACTION_REPEAT; +import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE; +import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND; +import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE; +import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP; +import static org.schabi.newpipe.player.helper.PlayerHelper.buildCloseOverlayLayoutParams; +import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; +import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimizeOnExitAction; +import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimumVideoHeight; +import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString; +import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked; +import static org.schabi.newpipe.player.helper.PlayerHelper.isPlaybackResumeEnabled; +import static org.schabi.newpipe.player.helper.PlayerHelper.nextRepeatMode; +import static org.schabi.newpipe.player.helper.PlayerHelper.nextResizeModeAndSaveToPrefs; +import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlaybackParametersFromPrefs; +import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlayerTypeFromIntent; +import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePopupLayoutParamsFromPrefs; +import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences; +import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParametersToPrefs; +import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex; +import static org.schabi.newpipe.util.ListHelper.getResolutionIndex; +import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; +import static org.schabi.newpipe.util.Localization.containsCaseInsensitive; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -94,7 +142,6 @@ import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamSegment; -import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.OnScrollBelowItemsListener; import org.schabi.newpipe.fragments.detail.VideoDetailFragment; @@ -127,12 +174,13 @@ import org.schabi.newpipe.player.resolver.VideoPlaybackResolver; import org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHelper; import org.schabi.newpipe.player.seekbarpreview.SeekbarPreviewThumbnailHolder; +import org.schabi.newpipe.util.StreamTypeUtil; import org.schabi.newpipe.util.DeviceUtils; -import org.schabi.newpipe.util.external_communication.KoreUtils; import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.PicassoHelper; import org.schabi.newpipe.util.SerializedCache; +import org.schabi.newpipe.util.external_communication.KoreUtils; import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.views.ExpandableSurfaceView; @@ -148,54 +196,6 @@ import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.disposables.SerialDisposable; -import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_AD_INSERTION; -import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_INTERNAL; -import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_PERIOD_TRANSITION; -import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK; -import static com.google.android.exoplayer2.Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT; -import static com.google.android.exoplayer2.Player.DiscontinuityReason; -import static com.google.android.exoplayer2.Player.EventListener; -import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL; -import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF; -import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE; -import static com.google.android.exoplayer2.Player.RepeatMode; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.schabi.newpipe.QueueItemMenuUtil.openPopupMenu; -import static org.schabi.newpipe.extractor.ServiceList.YouTube; -import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; -import static org.schabi.newpipe.ktx.ViewUtils.animate; -import static org.schabi.newpipe.ktx.ViewUtils.animateRotation; -import static org.schabi.newpipe.player.MainPlayer.ACTION_CLOSE; -import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD; -import static org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND; -import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT; -import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PAUSE; -import static org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS; -import static org.schabi.newpipe.player.MainPlayer.ACTION_RECREATE_NOTIFICATION; -import static org.schabi.newpipe.player.MainPlayer.ACTION_REPEAT; -import static org.schabi.newpipe.player.MainPlayer.ACTION_SHUFFLE; -import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND; -import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE; -import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP; -import static org.schabi.newpipe.player.helper.PlayerHelper.buildCloseOverlayLayoutParams; -import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; -import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimizeOnExitAction; -import static org.schabi.newpipe.player.helper.PlayerHelper.getMinimumVideoHeight; -import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString; -import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked; -import static org.schabi.newpipe.player.helper.PlayerHelper.isPlaybackResumeEnabled; -import static org.schabi.newpipe.player.helper.PlayerHelper.nextRepeatMode; -import static org.schabi.newpipe.player.helper.PlayerHelper.nextResizeModeAndSaveToPrefs; -import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlaybackParametersFromPrefs; -import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePlayerTypeFromIntent; -import static org.schabi.newpipe.player.helper.PlayerHelper.retrievePopupLayoutParamsFromPrefs; -import static org.schabi.newpipe.player.helper.PlayerHelper.retrieveSeekDurationFromPreferences; -import static org.schabi.newpipe.player.helper.PlayerHelper.savePlaybackParametersToPrefs; -import static org.schabi.newpipe.util.ListHelper.getPopupResolutionIndex; -import static org.schabi.newpipe.util.ListHelper.getResolutionIndex; -import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; -import static org.schabi.newpipe.util.Localization.containsCaseInsensitive; - public final class Player implements EventListener, PlaybackListener, @@ -1647,10 +1647,10 @@ private void triggerProgressUpdate() { // TODO: revert #6307 when introducing proper HLS support final int duration; if (currentItem != null - && currentItem.getStreamType() != StreamType.AUDIO_LIVE_STREAM - && currentItem.getStreamType() != StreamType.LIVE_STREAM) { + && !StreamTypeUtil.isLiveStream(currentItem.getStreamType()) + ) { // convert seconds to milliseconds - duration = (int) (currentItem.getDuration() * 1000); + duration = (int) (currentItem.getDuration() * 1000); } else { duration = (int) simpleExoPlayer.getDuration(); } @@ -2948,7 +2948,9 @@ private void onMetadataChanged(@NonNull final MediaSourceTag tag) { getVideoTitle(), getUploaderName(), showThumbnail ? Optional.ofNullable(getThumbnail()) : Optional.empty(), - tag.getMetadata().getDuration() + StreamTypeUtil.isLiveStream(tag.getMetadata().getStreamType()) + ? -1 + : tag.getMetadata().getDuration() ); notifyMetadataUpdateToListeners(); diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java index da478952ccb..ef0d8402934 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/MediaSessionManager.java @@ -70,6 +70,15 @@ public MediaSessionCompat.Token getSessionToken() { return mediaSession.getSessionToken(); } + /** + * sets the Metadata - if required. + * + * @param title {@link MediaMetadataCompat#METADATA_KEY_TITLE} + * @param artist {@link MediaMetadataCompat#METADATA_KEY_ARTIST} + * @param optAlbumArt {@link MediaMetadataCompat#METADATA_KEY_ALBUM_ART} + * @param duration {@link MediaMetadataCompat#METADATA_KEY_DURATION} + * - should be a negative value for unknown durations, e.g. for livestreams + */ public void setMetadata(@NonNull final String title, @NonNull final String artist, @NonNull final Optional optAlbumArt, @@ -95,7 +104,7 @@ public void setMetadata(@NonNull final String title, if (!checkIfMetadataShouldBeSet(title, artist, optAlbumArt, duration)) { if (DEBUG) { - Log.d(TAG, "setMetadata: No update required"); + Log.d(TAG, "setMetadata: No update required - exiting"); } return; } diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java index a6dcadd5eeb..81e629c2f30 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/PlaybackResolver.java @@ -14,6 +14,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.player.helper.PlayerDataSource; +import org.schabi.newpipe.util.StreamTypeUtil; public interface PlaybackResolver extends Resolver { @@ -21,7 +22,7 @@ public interface PlaybackResolver extends Resolver { default MediaSource maybeBuildLiveMediaSource(@NonNull final PlayerDataSource dataSource, @NonNull final StreamInfo info) { final StreamType streamType = info.getStreamType(); - if (!(streamType == StreamType.AUDIO_LIVE_STREAM || streamType == StreamType.LIVE_STREAM)) { + if (!StreamTypeUtil.isLiveStream(streamType)) { return null; } diff --git a/app/src/main/java/org/schabi/newpipe/util/StreamTypeUtil.java b/app/src/main/java/org/schabi/newpipe/util/StreamTypeUtil.java new file mode 100644 index 00000000000..87b3eed4f13 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/StreamTypeUtil.java @@ -0,0 +1,24 @@ +package org.schabi.newpipe.util; + +import org.schabi.newpipe.extractor.stream.StreamType; + +/** + * Utility class for {@link org.schabi.newpipe.extractor.stream.StreamType}. + */ +public final class StreamTypeUtil { + private StreamTypeUtil() { + // No impl pls + } + + /** + * Checks if the streamType is a livestream. + * + * @param streamType + * @return true when the streamType is a + * {@link StreamType#LIVE_STREAM} or {@link StreamType#AUDIO_LIVE_STREAM} + */ + public static boolean isLiveStream(final StreamType streamType) { + return streamType == StreamType.LIVE_STREAM + || streamType == StreamType.AUDIO_LIVE_STREAM; + } +}