From f8c3ec4be76c886b7262910bb61e5e25c3e43f68 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Sat, 4 Feb 2023 23:10:37 +0100 Subject: [PATCH 1/2] Use a whitelist to filter all streams retrieved by the extractor. NewPipe Extractor now extracts all YouTube Itags and therefore only those which can be handled by the player need to be retrieved from the list of all available streams. --- .../resolver/AudioPlaybackResolver.java | 6 +-- .../resolver/VideoPlaybackResolver.java | 8 ++-- .../org/schabi/newpipe/util/ListHelper.java | 38 ++++++++++++++----- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java index e87c93114..036df51dd 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java @@ -1,6 +1,6 @@ package org.schabi.newpipe.player.resolver; -import static org.schabi.newpipe.util.ListHelper.getNonTorrentStreams; +import static org.schabi.newpipe.util.ListHelper.getPlayableStreams; import android.content.Context; import android.util.Log; @@ -68,12 +68,12 @@ public class AudioPlaybackResolver implements PlaybackResolver { */ @Nullable private Stream getAudioSource(@NonNull final StreamInfo info) { - final List audioStreams = getNonTorrentStreams(info.getAudioStreams()); + final List audioStreams = getPlayableStreams(info.getAudioStreams()); if (!audioStreams.isEmpty()) { final int index = ListHelper.getDefaultAudioFormat(context, audioStreams); return getStreamForIndex(index, audioStreams); } else { - final List videoStreams = getNonTorrentStreams(info.getVideoStreams()); + final List videoStreams = getPlayableStreams(info.getVideoStreams()); if (!videoStreams.isEmpty()) { final int index = ListHelper.getDefaultResolutionIndex(context, videoStreams); return getStreamForIndex(index, videoStreams); diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java index cf7d73558..c3303266a 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java @@ -29,7 +29,7 @@ import java.util.Optional; import static com.google.android.exoplayer2.C.TIME_UNSET; import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams; -import static org.schabi.newpipe.util.ListHelper.getNonTorrentStreams; +import static org.schabi.newpipe.util.ListHelper.getPlayableStreams; public class VideoPlaybackResolver implements PlaybackResolver { private static final String TAG = VideoPlaybackResolver.class.getSimpleName(); @@ -72,8 +72,8 @@ public class VideoPlaybackResolver implements PlaybackResolver { // Create video stream source final List videoStreamsList = ListHelper.getSortedStreamVideosList(context, - getNonTorrentStreams(info.getVideoStreams()), - getNonTorrentStreams(info.getVideoOnlyStreams()), false, true); + getPlayableStreams(info.getVideoStreams()), + getPlayableStreams(info.getVideoOnlyStreams()), false, true); final int index; if (videoStreamsList.isEmpty()) { index = -1; @@ -100,7 +100,7 @@ public class VideoPlaybackResolver implements PlaybackResolver { } // Create optional audio stream source - final List audioStreams = getNonTorrentStreams(info.getAudioStreams()); + final List audioStreams = getPlayableStreams(info.getAudioStreams()); final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get( ListHelper.getDefaultAudioFormat(context, audioStreams)); diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java index b3b7c1792..f36866025 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java @@ -42,6 +42,21 @@ public final class ListHelper { // Use a Set for better performance private static final Set HIGH_RESOLUTION_LIST = Set.of("1440p", "2160p"); + /** + * List of supported YouTube Itag ids. + * The original order is kept. + * @see {@link org.schabi.newpipe.extractor.services.youtube.ItagItem#ITAG_LIST} + */ + private static final List SUPPORTED_ITAG_IDS = + List.of( + 17, 36, // video v3GPP + 18, 34, 35, 59, 78, 22, 37, 38, // video MPEG4 + 43, 44, 45, 46, // video webm + 171, 172, 139, 140, 141, 249, 250, 251, // audio + 160, 133, 134, 135, 212, 136, 298, 137, 299, 266, // video only + 278, 242, 243, 244, 245, 246, 247, 248, 271, 272, 302, 303, 308, 313, 315 + ); + private ListHelper() { } /** @@ -121,7 +136,7 @@ public final class ListHelper { */ @NonNull public static List getStreamsOfSpecifiedDelivery( - final List streamList, + @Nullable final List streamList, final DeliveryMethod deliveryMethod) { return getFilteredStreamList(streamList, stream -> stream.getDeliveryMethod() == deliveryMethod); @@ -136,23 +151,28 @@ public final class ListHelper { */ @NonNull public static List getUrlAndNonTorrentStreams( - final List streamList) { + @Nullable final List streamList) { return getFilteredStreamList(streamList, stream -> stream.isUrl() && stream.getDeliveryMethod() != DeliveryMethod.TORRENT); } /** - * Return a {@link Stream} list which only contains non-torrent streams. + * Return a {@link Stream} list which only contains streams which can be played by the player. + *
+ * Some formats are not supported. For more info, see {@link #SUPPORTED_ITAG_IDS}. + * Torrent streams are also removed, because they cannot be retrieved. * * @param streamList the original stream list * @param the item type's class that extends {@link Stream} - * @return a stream list which only contains non-torrent streams + * @return a stream list which only contains streams that can be played the player */ @NonNull - public static List getNonTorrentStreams( - final List streamList) { + public static List getPlayableStreams( + @Nullable final List streamList) { return getFilteredStreamList(streamList, - stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT); + stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT + && (stream.getItagItem() == null + || SUPPORTED_ITAG_IDS.contains(stream.getItagItem().id))); } /** @@ -199,7 +219,7 @@ public final class ListHelper { * @return a new stream list filtered using the given predicate */ private static List getFilteredStreamList( - final List streamList, + @Nullable final List streamList, final Predicate streamListPredicate) { if (streamList == null) { return Collections.emptyList(); @@ -210,7 +230,7 @@ public final class ListHelper { .collect(Collectors.toList()); } - private static String computeDefaultResolution(final Context context, final int key, + private static String computeDefaultResolution(@NonNull final Context context, final int key, final int value) { final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); From e18a6b09f8e76135b31bf41e3b7da11a1ab56581 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Mon, 17 Apr 2023 13:10:29 +0200 Subject: [PATCH 2/2] Apply new itag filter only to YouTube streams --- .../player/resolver/AudioPlaybackResolver.java | 6 ++++-- .../player/resolver/VideoPlaybackResolver.java | 7 ++++--- .../main/java/org/schabi/newpipe/util/ListHelper.java | 11 ++++++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java index 036df51dd..e1d3af335 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/AudioPlaybackResolver.java @@ -68,12 +68,14 @@ public class AudioPlaybackResolver implements PlaybackResolver { */ @Nullable private Stream getAudioSource(@NonNull final StreamInfo info) { - final List audioStreams = getPlayableStreams(info.getAudioStreams()); + final List audioStreams = getPlayableStreams( + info.getAudioStreams(), info.getServiceId()); if (!audioStreams.isEmpty()) { final int index = ListHelper.getDefaultAudioFormat(context, audioStreams); return getStreamForIndex(index, audioStreams); } else { - final List videoStreams = getPlayableStreams(info.getVideoStreams()); + final List videoStreams = getPlayableStreams( + info.getVideoStreams(), info.getServiceId()); if (!videoStreams.isEmpty()) { final int index = ListHelper.getDefaultResolutionIndex(context, videoStreams); return getStreamForIndex(index, videoStreams); diff --git a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java index c3303266a..0017312cf 100644 --- a/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java +++ b/app/src/main/java/org/schabi/newpipe/player/resolver/VideoPlaybackResolver.java @@ -72,8 +72,8 @@ public class VideoPlaybackResolver implements PlaybackResolver { // Create video stream source final List videoStreamsList = ListHelper.getSortedStreamVideosList(context, - getPlayableStreams(info.getVideoStreams()), - getPlayableStreams(info.getVideoOnlyStreams()), false, true); + getPlayableStreams(info.getVideoStreams(), info.getServiceId()), + getPlayableStreams(info.getVideoOnlyStreams(), info.getServiceId()), false, true); final int index; if (videoStreamsList.isEmpty()) { index = -1; @@ -100,7 +100,8 @@ public class VideoPlaybackResolver implements PlaybackResolver { } // Create optional audio stream source - final List audioStreams = getPlayableStreams(info.getAudioStreams()); + final List audioStreams = getPlayableStreams( + info.getAudioStreams(), info.getServiceId()); final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get( ListHelper.getDefaultAudioFormat(context, audioStreams)); diff --git a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java index f36866025..389bcc84f 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ListHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ListHelper.java @@ -1,5 +1,7 @@ package org.schabi.newpipe.util; +import static org.schabi.newpipe.extractor.ServiceList.YouTube; + import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; @@ -162,16 +164,19 @@ public final class ListHelper { * Some formats are not supported. For more info, see {@link #SUPPORTED_ITAG_IDS}. * Torrent streams are also removed, because they cannot be retrieved. * - * @param streamList the original stream list * @param the item type's class that extends {@link Stream} + * @param streamList the original stream list + * @param serviceId * @return a stream list which only contains streams that can be played the player */ @NonNull public static List getPlayableStreams( - @Nullable final List streamList) { + @Nullable final List streamList, final int serviceId) { + final int youtubeServiceId = YouTube.getServiceId(); return getFilteredStreamList(streamList, stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT - && (stream.getItagItem() == null + && (serviceId != youtubeServiceId + || stream.getItagItem() == null || SUPPORTED_ITAG_IDS.contains(stream.getItagItem().id))); }