Merge pull request #9748 from TeamNewPipe/feat/av1-tags
Add whitelist to only retrieve supported YouTube itags/streams
This commit is contained in:
commit
da30e539df
3 changed files with 45 additions and 17 deletions
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue