Merge pull request #9748 from TeamNewPipe/feat/av1-tags

Add whitelist to only retrieve supported YouTube itags/streams
This commit is contained in:
Stypox 2023-04-20 16:42:31 +02:00 committed by GitHub
commit da30e539df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 17 deletions

View file

@ -1,6 +1,6 @@
package org.schabi.newpipe.player.resolver; 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.content.Context;
import android.util.Log; import android.util.Log;
@ -68,12 +68,14 @@ public class AudioPlaybackResolver implements PlaybackResolver {
*/ */
@Nullable @Nullable
private Stream getAudioSource(@NonNull final StreamInfo info) { private Stream getAudioSource(@NonNull final StreamInfo info) {
final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams()); final List<AudioStream> audioStreams = getPlayableStreams(
info.getAudioStreams(), info.getServiceId());
if (!audioStreams.isEmpty()) { if (!audioStreams.isEmpty()) {
final int index = ListHelper.getDefaultAudioFormat(context, audioStreams); final int index = ListHelper.getDefaultAudioFormat(context, audioStreams);
return getStreamForIndex(index, audioStreams); return getStreamForIndex(index, audioStreams);
} else { } else {
final List<VideoStream> videoStreams = getNonTorrentStreams(info.getVideoStreams()); final List<VideoStream> videoStreams = getPlayableStreams(
info.getVideoStreams(), info.getServiceId());
if (!videoStreams.isEmpty()) { if (!videoStreams.isEmpty()) {
final int index = ListHelper.getDefaultResolutionIndex(context, videoStreams); final int index = ListHelper.getDefaultResolutionIndex(context, videoStreams);
return getStreamForIndex(index, videoStreams); return getStreamForIndex(index, videoStreams);

View file

@ -29,7 +29,7 @@ import java.util.Optional;
import static com.google.android.exoplayer2.C.TIME_UNSET; import static com.google.android.exoplayer2.C.TIME_UNSET;
import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams; 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 { public class VideoPlaybackResolver implements PlaybackResolver {
private static final String TAG = VideoPlaybackResolver.class.getSimpleName(); private static final String TAG = VideoPlaybackResolver.class.getSimpleName();
@ -72,8 +72,8 @@ public class VideoPlaybackResolver implements PlaybackResolver {
// Create video stream source // Create video stream source
final List<VideoStream> videoStreamsList = ListHelper.getSortedStreamVideosList(context, final List<VideoStream> videoStreamsList = ListHelper.getSortedStreamVideosList(context,
getNonTorrentStreams(info.getVideoStreams()), getPlayableStreams(info.getVideoStreams(), info.getServiceId()),
getNonTorrentStreams(info.getVideoOnlyStreams()), false, true); getPlayableStreams(info.getVideoOnlyStreams(), info.getServiceId()), false, true);
final int index; final int index;
if (videoStreamsList.isEmpty()) { if (videoStreamsList.isEmpty()) {
index = -1; index = -1;
@ -100,7 +100,8 @@ public class VideoPlaybackResolver implements PlaybackResolver {
} }
// Create optional audio stream source // Create optional audio stream source
final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams()); final List<AudioStream> audioStreams = getPlayableStreams(
info.getAudioStreams(), info.getServiceId());
final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get( final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get(
ListHelper.getDefaultAudioFormat(context, audioStreams)); ListHelper.getDefaultAudioFormat(context, audioStreams));

View file

@ -1,5 +1,7 @@
package org.schabi.newpipe.util; package org.schabi.newpipe.util;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
@ -42,6 +44,21 @@ public final class ListHelper {
// Use a Set for better performance // Use a Set for better performance
private static final Set<String> HIGH_RESOLUTION_LIST = Set.of("1440p", "2160p"); private static final Set<String> 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<Integer> 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() { } private ListHelper() { }
/** /**
@ -121,7 +138,7 @@ public final class ListHelper {
*/ */
@NonNull @NonNull
public static <S extends Stream> List<S> getStreamsOfSpecifiedDelivery( public static <S extends Stream> List<S> getStreamsOfSpecifiedDelivery(
final List<S> streamList, @Nullable final List<S> streamList,
final DeliveryMethod deliveryMethod) { final DeliveryMethod deliveryMethod) {
return getFilteredStreamList(streamList, return getFilteredStreamList(streamList,
stream -> stream.getDeliveryMethod() == deliveryMethod); stream -> stream.getDeliveryMethod() == deliveryMethod);
@ -136,23 +153,31 @@ public final class ListHelper {
*/ */
@NonNull @NonNull
public static <S extends Stream> List<S> getUrlAndNonTorrentStreams( public static <S extends Stream> List<S> getUrlAndNonTorrentStreams(
final List<S> streamList) { @Nullable final List<S> streamList) {
return getFilteredStreamList(streamList, return getFilteredStreamList(streamList,
stream -> stream.isUrl() && stream.getDeliveryMethod() != DeliveryMethod.TORRENT); 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.
* <br>
* 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 <S> the item type's class that extends {@link Stream} * @param <S> the item type's class that extends {@link Stream}
* @return a stream list which only contains non-torrent streams * @param streamList the original stream list
* @param serviceId
* @return a stream list which only contains streams that can be played the player
*/ */
@NonNull @NonNull
public static <S extends Stream> List<S> getNonTorrentStreams( public static <S extends Stream> List<S> getPlayableStreams(
final List<S> streamList) { @Nullable final List<S> streamList, final int serviceId) {
final int youtubeServiceId = YouTube.getServiceId();
return getFilteredStreamList(streamList, return getFilteredStreamList(streamList,
stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT); stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT
&& (serviceId != youtubeServiceId
|| stream.getItagItem() == null
|| SUPPORTED_ITAG_IDS.contains(stream.getItagItem().id)));
} }
/** /**
@ -199,7 +224,7 @@ public final class ListHelper {
* @return a new stream list filtered using the given predicate * @return a new stream list filtered using the given predicate
*/ */
private static <S extends Stream> List<S> getFilteredStreamList( private static <S extends Stream> List<S> getFilteredStreamList(
final List<S> streamList, @Nullable final List<S> streamList,
final Predicate<S> streamListPredicate) { final Predicate<S> streamListPredicate) {
if (streamList == null) { if (streamList == null) {
return Collections.emptyList(); return Collections.emptyList();
@ -210,7 +235,7 @@ public final class ListHelper {
.collect(Collectors.toList()); .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 int value) {
final SharedPreferences preferences = final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context); PreferenceManager.getDefaultSharedPreferences(context);