NewPipe-app-android/app/src/main/java/org/schabi/newpipe/util/ListHelper.java

880 lines
39 KiB
Java
Raw Normal View History

package org.schabi.newpipe.util;
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import androidx.annotation.NonNull;
2020-05-18 11:44:24 +02:00
import androidx.annotation.Nullable;
2019-10-04 14:59:08 +02:00
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.AudioStream;
2023-03-19 03:06:29 +01:00
import org.schabi.newpipe.extractor.stream.AudioTrackType;
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
import org.schabi.newpipe.extractor.stream.DeliveryMethod;
import org.schabi.newpipe.extractor.stream.Stream;
import org.schabi.newpipe.extractor.stream.VideoStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
2023-03-17 21:51:40 +01:00
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public final class ListHelper {
// Video format in order of quality. 0=lowest quality, n=highest quality
private static final List<MediaFormat> VIDEO_FORMAT_QUALITY_RANKING =
2022-07-15 04:10:29 +02:00
List.of(MediaFormat.v3GPP, MediaFormat.WEBM, MediaFormat.MPEG_4);
// Audio format in order of quality. 0=lowest quality, n=highest quality
private static final List<MediaFormat> AUDIO_FORMAT_QUALITY_RANKING =
2022-07-15 04:10:29 +02:00
List.of(MediaFormat.MP3, MediaFormat.WEBMA, MediaFormat.M4A);
// Audio format in order of efficiency. 0=least efficient, n=most efficient
private static final List<MediaFormat> AUDIO_FORMAT_EFFICIENCY_RANKING =
List.of(MediaFormat.MP3, MediaFormat.M4A, MediaFormat.WEBMA);
2022-07-15 04:10:25 +02:00
// Use a Set for better performance
private static final Set<String> HIGH_RESOLUTION_LIST = Set.of("1440p", "2160p");
// Audio track types in order of priority. 0=lowest, n=highest
private static final List<AudioTrackType> AUDIO_TRACK_TYPE_RANKING =
List.of(AudioTrackType.DESCRIPTIVE, AudioTrackType.DUBBED, AudioTrackType.ORIGINAL);
// Audio track types in order of priority when descriptive audio is preferred.
private static final List<AudioTrackType> AUDIO_TRACK_TYPE_RANKING_DESCRIPTIVE =
List.of(AudioTrackType.ORIGINAL, AudioTrackType.DUBBED, AudioTrackType.DESCRIPTIVE);
/**
* 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() { }
/**
* @param context Android app context
* @param videoStreams list of the video streams to check
* @return index of the video stream with the default index
2023-03-17 21:51:40 +01:00
* @see #getDefaultResolutionIndex(String, String, MediaFormat, List)
*/
public static int getDefaultResolutionIndex(final Context context,
final List<VideoStream> videoStreams) {
2020-08-16 10:24:58 +02:00
final String defaultResolution = computeDefaultResolution(context,
R.string.default_resolution_key, R.string.default_resolution_value);
return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams);
}
/**
* @param context Android app context
* @param videoStreams list of the video streams to check
* @param defaultResolution the default resolution to look for
* @return index of the video stream with the default index
2023-03-17 21:51:40 +01:00
* @see #getDefaultResolutionIndex(String, String, MediaFormat, List)
*/
public static int getResolutionIndex(final Context context,
final List<VideoStream> videoStreams,
final String defaultResolution) {
return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams);
}
/**
2023-03-17 21:51:40 +01:00
* @param context Android app context
* @param videoStreams list of the video streams to check
* @return index of the video stream with the default index
2023-03-17 21:51:40 +01:00
* @see #getDefaultResolutionIndex(String, String, MediaFormat, List)
*/
public static int getPopupDefaultResolutionIndex(final Context context,
final List<VideoStream> videoStreams) {
2020-08-16 10:24:58 +02:00
final String defaultResolution = computeDefaultResolution(context,
R.string.default_popup_resolution_key, R.string.default_popup_resolution_value);
return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams);
}
/**
* @param context Android app context
* @param videoStreams list of the video streams to check
* @param defaultResolution the default resolution to look for
* @return index of the video stream with the default index
2023-03-17 21:51:40 +01:00
* @see #getDefaultResolutionIndex(String, String, MediaFormat, List)
*/
public static int getPopupResolutionIndex(final Context context,
final List<VideoStream> videoStreams,
final String defaultResolution) {
return getDefaultResolutionWithDefaultFormat(context, defaultResolution, videoStreams);
}
public static int getDefaultAudioFormat(final Context context,
final List<AudioStream> audioStreams) {
2023-03-19 23:37:52 +01:00
return getAudioIndexByHighestRank(audioStreams,
getAudioTrackComparator(context).thenComparing(getAudioFormatComparator(context)));
}
public static int getDefaultAudioTrackGroup(final Context context,
final List<List<AudioStream>> groupedAudioStreams) {
if (groupedAudioStreams == null || groupedAudioStreams.isEmpty()) {
return -1;
}
final Comparator<AudioStream> cmp = getAudioTrackComparator(context);
final List<AudioStream> highestRanked = groupedAudioStreams.stream()
.max((o1, o2) -> cmp.compare(o1.get(0), o2.get(0)))
.orElse(null);
return groupedAudioStreams.indexOf(highestRanked);
}
public static int getAudioFormatIndex(final Context context,
final List<AudioStream> audioStreams,
@Nullable final String trackId) {
if (trackId != null) {
for (int i = 0; i < audioStreams.size(); i++) {
final AudioStream s = audioStreams.get(i);
if (s.getAudioTrackId() != null
&& s.getAudioTrackId().equals(trackId)) {
return i;
}
}
}
return getDefaultAudioFormat(context, audioStreams);
}
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
/**
* Return a {@link Stream} list which uses the given delivery method from a {@link Stream}
* list.
*
* @param streamList the original {@link Stream stream} list
* @param deliveryMethod the {@link DeliveryMethod delivery method}
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
* @param <S> the item type's class that extends {@link Stream}
* @return a {@link Stream stream} list which uses the given delivery method
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
*/
@NonNull
public static <S extends Stream> List<S> getStreamsOfSpecifiedDelivery(
@Nullable final List<S> streamList,
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
final DeliveryMethod deliveryMethod) {
return getFilteredStreamList(streamList,
stream -> stream.getDeliveryMethod() == deliveryMethod);
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
}
/**
* Return a {@link Stream} list which only contains URL streams and non-torrent streams.
*
* @param streamList the original stream list
* @param <S> the item type's class that extends {@link Stream}
* @return a stream list which only contains URL streams and non-torrent streams
*/
@NonNull
public static <S extends Stream> List<S> getUrlAndNonTorrentStreams(
@Nullable final List<S> streamList) {
return getFilteredStreamList(streamList,
stream -> stream.isUrl() && stream.getDeliveryMethod() != DeliveryMethod.TORRENT);
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
}
/**
* Return a {@link Stream} list which only contains streams which can be played by the player.
*
* <p>
* Some formats are not supported, see {@link #SUPPORTED_ITAG_IDS} for more details.
* Torrent streams are also removed, because they cannot be retrieved, like OPUS streams using
* HLS as their delivery method, since they are not supported by ExoPlayer.
* </p>
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
*
* @param <S> the item type's class that extends {@link Stream}
* @param streamList the original stream list
* @param serviceId the service ID from which the streams' list comes from
* @return a stream list which only contains streams that can be played the player
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
*/
@NonNull
public static <S extends Stream> List<S> getPlayableStreams(
@Nullable final List<S> streamList, final int serviceId) {
final int youtubeServiceId = YouTube.getServiceId();
return getFilteredStreamList(streamList,
stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT
&& (stream.getDeliveryMethod() != DeliveryMethod.HLS
|| stream.getFormat() != MediaFormat.OPUS)
&& (serviceId != youtubeServiceId
|| stream.getItagItem() == null
|| SUPPORTED_ITAG_IDS.contains(stream.getItagItem().id)));
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
}
/**
* Join the two lists of video streams (video_only and normal videos),
* and sort them according with default format chosen by the user.
*
* @param context the context to search for the format to give preference
* @param videoStreams the normal videos list
* @param videoOnlyStreams the video-only stream list
* @param ascendingOrder true -> smallest to greatest | false -> greatest to smallest
* @param preferVideoOnlyStreams if video-only streams should preferred when both video-only
* streams and normal video streams are available
* @return the sorted list
*/
@NonNull
public static List<VideoStream> getSortedStreamVideosList(
@NonNull final Context context,
@Nullable final List<VideoStream> videoStreams,
@Nullable final List<VideoStream> videoOnlyStreams,
final boolean ascendingOrder,
final boolean preferVideoOnlyStreams) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
2020-08-16 10:24:58 +02:00
final boolean showHigherResolutions = preferences.getBoolean(
context.getString(R.string.show_higher_resolutions_key), false);
2020-08-16 10:24:58 +02:00
final MediaFormat defaultFormat = getDefaultFormat(context,
R.string.default_video_format_key, R.string.default_video_format_value);
return getSortedStreamVideosList(defaultFormat, showHigherResolutions, videoStreams,
videoOnlyStreams, ascendingOrder, preferVideoOnlyStreams);
}
/**
* Get a sorted list containing a set of default resolution info
* and additional resolution info if showHigherResolutions is true.
*
* @param resources the resources to get the resolutions from
* @param defaultResolutionKey the settings key of the default resolution
* @param additionalResolutionKey the settings key of the additional resolutions
* @param showHigherResolutions if higher resolutions should be included in the sorted list
* @return a sorted list containing the default and maybe additional resolutions
*/
public static List<String> getSortedResolutionList(
final Resources resources,
final int defaultResolutionKey,
final int additionalResolutionKey,
final boolean showHigherResolutions) {
final List<String> resolutions = new ArrayList<>(Arrays.asList(
resources.getStringArray(defaultResolutionKey)));
if (!showHigherResolutions) {
return resolutions;
}
final List<String> additionalResolutions = Arrays.asList(
resources.getStringArray(additionalResolutionKey));
// keep "best resolution" at the top
resolutions.addAll(1, additionalResolutions);
return resolutions;
}
public static boolean isHighResolutionSelected(final String selectedResolution,
final int additionalResolutionKey,
final Resources resources) {
return Arrays.asList(resources.getStringArray(
additionalResolutionKey))
.contains(selectedResolution);
}
/**
* Filter the list of audio streams and return a list with the preferred stream for
* each audio track. Streams are sorted with the preferred language in the first position.
*
* @param context the context to search for the track to give preference
* @param audioStreams the list of audio streams
* @return the sorted, filtered list
*/
2023-03-17 21:51:40 +01:00
public static List<AudioStream> getFilteredAudioStreams(
@NonNull final Context context,
@Nullable final List<AudioStream> audioStreams) {
if (audioStreams == null) {
return Collections.emptyList();
}
final HashMap<String, AudioStream> collectedStreams = new HashMap<>();
2023-03-19 23:37:52 +01:00
final Comparator<AudioStream> cmp = getAudioFormatComparator(context);
2023-03-17 21:51:40 +01:00
for (final AudioStream stream : audioStreams) {
if (stream.getDeliveryMethod() == DeliveryMethod.TORRENT
|| (stream.getDeliveryMethod() == DeliveryMethod.HLS
&& stream.getFormat() == MediaFormat.OPUS)) {
2023-03-17 21:51:40 +01:00
continue;
}
2023-03-18 16:28:09 +01:00
final String trackId = Objects.toString(stream.getAudioTrackId(), "");
2023-03-17 21:51:40 +01:00
final AudioStream presentStream = collectedStreams.get(trackId);
if (presentStream == null || cmp.compare(stream, presentStream) > 0) {
collectedStreams.put(trackId, stream);
}
}
2023-03-19 03:06:29 +01:00
// Filter unknown audio tracks if there are multiple tracks
if (collectedStreams.size() > 1) {
2023-03-19 22:55:37 +01:00
collectedStreams.remove("");
2023-03-19 03:06:29 +01:00
}
// Sort collected streams by name
return collectedStreams.values().stream().sorted(getAudioTrackNameComparator(context))
.collect(Collectors.toList());
}
/**
* Group the list of audioStreams by their track ID and sort the resulting list by track name.
*
* @param context app context to get track names for sorting
* @param audioStreams list of audio streams
* @return list of audio streams lists representing individual tracks
*/
public static List<List<AudioStream>> getGroupedAudioStreams(
@NonNull final Context context,
@Nullable final List<AudioStream> audioStreams) {
if (audioStreams == null) {
return Collections.emptyList();
}
final HashMap<String, List<AudioStream>> collectedStreams = new HashMap<>();
for (final AudioStream stream : audioStreams) {
final String trackId = Objects.toString(stream.getAudioTrackId(), "");
if (collectedStreams.containsKey(trackId)) {
collectedStreams.get(trackId).add(stream);
} else {
final List<AudioStream> list = new ArrayList<>();
list.add(stream);
collectedStreams.put(trackId, list);
}
}
// Filter unknown audio tracks if there are multiple tracks
if (collectedStreams.size() > 1) {
collectedStreams.remove("");
}
// Sort tracks alphabetically, sort track streams by quality
final Comparator<AudioStream> nameCmp = getAudioTrackNameComparator(context);
final Comparator<AudioStream> formatCmp = getAudioFormatComparator(context);
return collectedStreams.values().stream()
.sorted((o1, o2) -> nameCmp.compare(o1.get(0), o2.get(0)))
.map(streams -> streams.stream().sorted(formatCmp).collect(Collectors.toList()))
.collect(Collectors.toList());
2023-03-17 21:51:40 +01:00
}
/*//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////*/
/**
* Get a filtered stream list, by using Java 8 Stream's API and the given predicate.
*
* @param streamList the stream list to filter
* @param streamListPredicate the predicate which will be used to filter streams
* @param <S> the item type's class that extends {@link Stream}
* @return a new stream list filtered using the given predicate
*/
private static <S extends Stream> List<S> getFilteredStreamList(
@Nullable final List<S> streamList,
final Predicate<S> streamListPredicate) {
if (streamList == null) {
return Collections.emptyList();
}
return streamList.stream()
.filter(streamListPredicate)
.collect(Collectors.toList());
}
private static String computeDefaultResolution(@NonNull final Context context, final int key,
final int value) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
2020-11-22 10:39:00 +01:00
// Load the preferred resolution otherwise the best available
String resolution = preferences != null
? preferences.getString(context.getString(key), context.getString(value))
: context.getString(R.string.best_resolution_key);
2020-08-16 10:24:58 +02:00
final String maxResolution = getResolutionLimit(context);
if (maxResolution != null
&& (resolution.equals(context.getString(R.string.best_resolution_key))
|| compareVideoStreamResolution(maxResolution, resolution) < 1)) {
resolution = maxResolution;
}
return resolution;
}
/**
* Return the index of the default stream in the list, that will be sorted in the process, based
* on the parameters defaultResolution and defaultFormat.
*
* @param defaultResolution the default resolution to look for
* @param bestResolutionKey key of the best resolution
2020-11-22 10:39:00 +01:00
* @param defaultFormat the default format to look for
* @param videoStreams a mutable list of the video streams to check (it will be sorted in
* place)
* @return index of the default resolution&format in the sorted videoStreams
*/
static int getDefaultResolutionIndex(final String defaultResolution,
final String bestResolutionKey,
final MediaFormat defaultFormat,
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
@Nullable final List<VideoStream> videoStreams) {
if (videoStreams == null || videoStreams.isEmpty()) {
return -1;
}
sortStreamList(videoStreams, false);
if (defaultResolution.equals(bestResolutionKey)) {
return 0;
}
final int defaultStreamIndex =
getVideoStreamIndex(defaultResolution, defaultFormat, videoStreams);
// this is actually an error,
// but maybe there is really no stream fitting to the default value.
if (defaultStreamIndex == -1) {
return 0;
}
return defaultStreamIndex;
}
/**
* Join the two lists of video streams (video_only and normal videos),
* and sort them according with default format chosen by the user.
*
* @param defaultFormat format to give preference
* @param showHigherResolutions show >1080p resolutions
* @param videoStreams normal videos list
* @param videoOnlyStreams video only stream list
* @param ascendingOrder true -> smallest to greatest | false -> greatest to smallest
* @param preferVideoOnlyStreams if video-only streams should preferred when both video-only
* streams and normal video streams are available
* @return the sorted list
*/
@NonNull
static List<VideoStream> getSortedStreamVideosList(
@Nullable final MediaFormat defaultFormat,
final boolean showHigherResolutions,
@Nullable final List<VideoStream> videoStreams,
@Nullable final List<VideoStream> videoOnlyStreams,
final boolean ascendingOrder,
final boolean preferVideoOnlyStreams
) {
// Determine order of streams
// The last added list is preferred
final List<List<VideoStream>> videoStreamsOrdered =
preferVideoOnlyStreams
? Arrays.asList(videoStreams, videoOnlyStreams)
: Arrays.asList(videoOnlyStreams, videoStreams);
final List<VideoStream> allInitialStreams = videoStreamsOrdered.stream()
// Ignore lists that are null
.filter(Objects::nonNull)
.flatMap(List::stream)
// Filter out higher resolutions (or not if high resolutions should always be shown)
.filter(stream -> showHigherResolutions
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
|| !HIGH_RESOLUTION_LIST.contains(stream.getResolution()
2023-03-17 21:51:40 +01:00
// Replace any frame rate with nothing
.replaceAll("p\\d+$", "p")))
.collect(Collectors.toList());
final HashMap<String, VideoStream> hashMap = new HashMap<>();
// Add all to the hashmap
for (final VideoStream videoStream : allInitialStreams) {
hashMap.put(videoStream.getResolution(), videoStream);
}
// Override the values when the key == resolution, with the defaultFormat
for (final VideoStream videoStream : allInitialStreams) {
if (videoStream.getFormat() == defaultFormat) {
hashMap.put(videoStream.getResolution(), videoStream);
}
}
// Return the sorted list
return sortStreamList(new ArrayList<>(hashMap.values()), ascendingOrder);
}
/**
* Sort the streams list depending on the parameter ascendingOrder;
* <p>
* It works like that:<br>
* - Take a string resolution, remove the letters, replace "0p60" (for 60fps videos) with "1"
* and sort by the greatest:<br>
* <blockquote><pre>
* 720p -> 720
* 720p60 -> 721
* 360p -> 360
* 1080p -> 1080
* 1080p60 -> 1081
* <br>
* ascendingOrder ? 360 < 720 < 721 < 1080 < 1081
* !ascendingOrder ? 1081 < 1080 < 721 < 720 < 360</pre></blockquote>
*
* @param videoStreams list that the sorting will be applied
* @param ascendingOrder true -> smallest to greatest | false -> greatest to smallest
* @return The sorted list (same reference as parameter videoStreams)
*/
private static List<VideoStream> sortStreamList(final List<VideoStream> videoStreams,
final boolean ascendingOrder) {
// Compares the quality of two video streams.
final Comparator<VideoStream> comparator = Comparator.nullsLast(Comparator
.comparing(VideoStream::getResolution, ListHelper::compareVideoStreamResolution)
.thenComparingInt(s -> VIDEO_FORMAT_QUALITY_RANKING.indexOf(s.getFormat())));
Collections.sort(videoStreams, ascendingOrder ? comparator : comparator.reversed());
return videoStreams;
}
/**
* Get the audio-stream from the list with the highest rank, depending on the comparator.
* Format will be ignored if it yields no results.
*
* @param audioStreams List of audio streams
* @param comparator The comparator used for determining the max/best/highest ranked value
2021-11-22 20:02:31 +01:00
* @return Index of audio stream that produces the highest ranked result or -1 if not found
*/
2023-03-19 23:37:52 +01:00
static int getAudioIndexByHighestRank(@Nullable final List<AudioStream> audioStreams,
final Comparator<AudioStream> comparator) {
if (audioStreams == null || audioStreams.isEmpty()) {
return -1;
}
final AudioStream highestRankedAudioStream = audioStreams.stream()
2023-03-19 23:37:52 +01:00
.max(comparator).orElse(null);
return audioStreams.indexOf(highestRankedAudioStream);
}
/**
* Locates a possible match for the given resolution and format in the provided list.
*
* <p>In this order:</p>
*
* <ol>
* <li>Find a format and resolution match</li>
* <li>Find a format and resolution match and ignore the refresh</li>
* <li>Find a resolution match</li>
* <li>Find a resolution match and ignore the refresh</li>
* <li>Find a resolution just below the requested resolution and ignore the refresh</li>
* <li>Give up</li>
* </ol>
*
* @param targetResolution the resolution to look for
* @param targetFormat the format to look for
* @param videoStreams the available video streams
2020-11-22 10:39:00 +01:00
* @return the index of the preferred video stream
*/
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
static int getVideoStreamIndex(@NonNull final String targetResolution,
final MediaFormat targetFormat,
@NonNull final List<VideoStream> videoStreams) {
int fullMatchIndex = -1;
int fullMatchNoRefreshIndex = -1;
int resMatchOnlyIndex = -1;
int resMatchOnlyNoRefreshIndex = -1;
int lowerResMatchNoRefreshIndex = -1;
2020-08-16 10:24:58 +02:00
final String targetResolutionNoRefresh = targetResolution.replaceAll("p\\d+$", "p");
for (int idx = 0; idx < videoStreams.size(); idx++) {
final MediaFormat format = targetFormat == null
? null
: videoStreams.get(idx).getFormat();
2020-08-16 10:24:58 +02:00
final String resolution = videoStreams.get(idx).getResolution();
final String resolutionNoRefresh = resolution.replaceAll("p\\d+$", "p");
if (format == targetFormat && resolution.equals(targetResolution)) {
fullMatchIndex = idx;
}
if (format == targetFormat && resolutionNoRefresh.equals(targetResolutionNoRefresh)) {
fullMatchNoRefreshIndex = idx;
}
if (resMatchOnlyIndex == -1 && resolution.equals(targetResolution)) {
resMatchOnlyIndex = idx;
}
if (resMatchOnlyNoRefreshIndex == -1
&& resolutionNoRefresh.equals(targetResolutionNoRefresh)) {
resMatchOnlyNoRefreshIndex = idx;
}
if (lowerResMatchNoRefreshIndex == -1 && compareVideoStreamResolution(
resolutionNoRefresh, targetResolutionNoRefresh) < 0) {
lowerResMatchNoRefreshIndex = idx;
}
}
if (fullMatchIndex != -1) {
return fullMatchIndex;
}
if (fullMatchNoRefreshIndex != -1) {
return fullMatchNoRefreshIndex;
}
if (resMatchOnlyIndex != -1) {
return resMatchOnlyIndex;
}
if (resMatchOnlyNoRefreshIndex != -1) {
return resMatchOnlyNoRefreshIndex;
}
return lowerResMatchNoRefreshIndex;
}
/**
* Fetches the desired resolution or returns the default if it is not found.
* The resolution will be reduced if video chocking is active.
*
* @param context Android app context
* @param defaultResolution the default resolution
* @param videoStreams the list of video streams to check
2020-11-22 10:39:00 +01:00
* @return the index of the preferred video stream
*/
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
private static int getDefaultResolutionWithDefaultFormat(@NonNull final Context context,
final String defaultResolution,
final List<VideoStream> videoStreams) {
2020-08-16 10:24:58 +02:00
final MediaFormat defaultFormat = getDefaultFormat(context,
R.string.default_video_format_key, R.string.default_video_format_value);
return getDefaultResolutionIndex(defaultResolution,
context.getString(R.string.best_resolution_key), defaultFormat, videoStreams);
}
@Nullable
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
private static MediaFormat getDefaultFormat(@NonNull final Context context,
@StringRes final int defaultFormatKey,
@StringRes final int defaultFormatValueKey) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
2020-08-16 10:24:58 +02:00
final String defaultFormat = context.getString(defaultFormatValueKey);
final String defaultFormatString = preferences.getString(
context.getString(defaultFormatKey),
defaultFormat
);
return getMediaFormatFromKey(context, defaultFormatString);
}
@Nullable
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
private static MediaFormat getMediaFormatFromKey(@NonNull final Context context,
@NonNull final String formatKey) {
MediaFormat format = null;
if (formatKey.equals(context.getString(R.string.video_webm_key))) {
format = MediaFormat.WEBM;
} else if (formatKey.equals(context.getString(R.string.video_mp4_key))) {
format = MediaFormat.MPEG_4;
} else if (formatKey.equals(context.getString(R.string.video_3gp_key))) {
format = MediaFormat.v3GPP;
} else if (formatKey.equals(context.getString(R.string.audio_webm_key))) {
format = MediaFormat.WEBMA;
} else if (formatKey.equals(context.getString(R.string.audio_m4a_key))) {
format = MediaFormat.M4A;
}
return format;
}
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
private static int compareVideoStreamResolution(@NonNull final String r1,
@NonNull final String r2) {
try {
final int res1 = Integer.parseInt(r1.replaceAll("0p\\d+$", "1")
.replaceAll("[^\\d.]", ""));
final int res2 = Integer.parseInt(r2.replaceAll("0p\\d+$", "1")
.replaceAll("[^\\d.]", ""));
return res1 - res2;
} catch (final NumberFormatException e) {
// Consider the first one greater because we don't know if the two streams are
// different or not (a NumberFormatException was thrown so we don't know the resolution
// of one stream or of all streams)
return 1;
}
}
static boolean isLimitingDataUsage(@NonNull final Context context) {
return getResolutionLimit(context) != null;
}
/**
* The maximum resolution allowed.
*
* @param context App context
* @return maximum resolution allowed or null if there is no maximum
*/
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
private static String getResolutionLimit(@NonNull final Context context) {
String resolutionLimit = null;
New MP4 muxer + Queue changes + Storage fixes Main changes: * correctly check the available space (CircularFile.java) * misc cleanup (CircularFile.java) * use the "Error Reporter" for non-http errors * rewrite network state checking and add better support for API 21 (Lollipop) or higher * implement "metered networks" * add buttons in "Downloads" activity to start/pause all pending downloads, ignoring the queue flag or if the network is "metered" * add workaround for VPN connections and/or network switching. Example: switching WiFi to 3G * rewrite DataReader ¡Webm muxer is now 57% more faster! * rewrite CircularFile, use file buffers instead of memory buffers. Less troubles in low-end devices * fix missing offset for KaxCluster (WebMWriter.java), manifested as no thumbnails on file explorers Download queue: * remember queue status, unless the user pause the download (un-queue) * semi-automatic downloads, between networks. Effective if the user create a new download or the downloads activity is starts * allow enqueue failed downloads * new option, queue limit, enabled by default. Used to allow one or multiple downloads at same time Miscellaneous: * fix crash while selecting details/error menu (mistake on MissionFragment.java) * misc serialize changes (DownloadMission.java) * minor UI tweaks * allow overwrite paused downloads * fix wrong icons for grid/list button in downloads * add share option * implement #2006 * correct misspelled word in strings.xml (es) (cmn) * fix MissionAdapter crash during device shutdown New Mp4Muxer + required changes: * new mp4 muxer (from dash only) with this, muxing on Android 7 is possible now!!! * re-work in SharpStream * drop mp4 dash muxer * misc changes: add warning in SecondaryStreamHelper.java, * strip m4a DASH files to normal m4a format (youtube only) Fix storage issues: * warn to the user if is choosing a "read only" download directory (for external SD Cards), useless is rooted :) * "write proof" allow post-processing resuming only if the device ran out of space * implement "insufficient storage" error for downloads
2019-03-23 02:54:07 +01:00
if (isMeteredNetwork(context)) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
2020-08-16 10:24:58 +02:00
final String defValue = context.getString(R.string.limit_data_usage_none_key);
final String value = preferences.getString(
context.getString(R.string.limit_mobile_data_usage_key), defValue);
New MP4 muxer + Queue changes + Storage fixes Main changes: * correctly check the available space (CircularFile.java) * misc cleanup (CircularFile.java) * use the "Error Reporter" for non-http errors * rewrite network state checking and add better support for API 21 (Lollipop) or higher * implement "metered networks" * add buttons in "Downloads" activity to start/pause all pending downloads, ignoring the queue flag or if the network is "metered" * add workaround for VPN connections and/or network switching. Example: switching WiFi to 3G * rewrite DataReader ¡Webm muxer is now 57% more faster! * rewrite CircularFile, use file buffers instead of memory buffers. Less troubles in low-end devices * fix missing offset for KaxCluster (WebMWriter.java), manifested as no thumbnails on file explorers Download queue: * remember queue status, unless the user pause the download (un-queue) * semi-automatic downloads, between networks. Effective if the user create a new download or the downloads activity is starts * allow enqueue failed downloads * new option, queue limit, enabled by default. Used to allow one or multiple downloads at same time Miscellaneous: * fix crash while selecting details/error menu (mistake on MissionFragment.java) * misc serialize changes (DownloadMission.java) * minor UI tweaks * allow overwrite paused downloads * fix wrong icons for grid/list button in downloads * add share option * implement #2006 * correct misspelled word in strings.xml (es) (cmn) * fix MissionAdapter crash during device shutdown New Mp4Muxer + required changes: * new mp4 muxer (from dash only) with this, muxing on Android 7 is possible now!!! * re-work in SharpStream * drop mp4 dash muxer * misc changes: add warning in SecondaryStreamHelper.java, * strip m4a DASH files to normal m4a format (youtube only) Fix storage issues: * warn to the user if is choosing a "read only" download directory (for external SD Cards), useless is rooted :) * "write proof" allow post-processing resuming only if the device ran out of space * implement "insufficient storage" error for downloads
2019-03-23 02:54:07 +01:00
resolutionLimit = defValue.equals(value) ? null : value;
}
return resolutionLimit;
}
/**
New MP4 muxer + Queue changes + Storage fixes Main changes: * correctly check the available space (CircularFile.java) * misc cleanup (CircularFile.java) * use the "Error Reporter" for non-http errors * rewrite network state checking and add better support for API 21 (Lollipop) or higher * implement "metered networks" * add buttons in "Downloads" activity to start/pause all pending downloads, ignoring the queue flag or if the network is "metered" * add workaround for VPN connections and/or network switching. Example: switching WiFi to 3G * rewrite DataReader ¡Webm muxer is now 57% more faster! * rewrite CircularFile, use file buffers instead of memory buffers. Less troubles in low-end devices * fix missing offset for KaxCluster (WebMWriter.java), manifested as no thumbnails on file explorers Download queue: * remember queue status, unless the user pause the download (un-queue) * semi-automatic downloads, between networks. Effective if the user create a new download or the downloads activity is starts * allow enqueue failed downloads * new option, queue limit, enabled by default. Used to allow one or multiple downloads at same time Miscellaneous: * fix crash while selecting details/error menu (mistake on MissionFragment.java) * misc serialize changes (DownloadMission.java) * minor UI tweaks * allow overwrite paused downloads * fix wrong icons for grid/list button in downloads * add share option * implement #2006 * correct misspelled word in strings.xml (es) (cmn) * fix MissionAdapter crash during device shutdown New Mp4Muxer + required changes: * new mp4 muxer (from dash only) with this, muxing on Android 7 is possible now!!! * re-work in SharpStream * drop mp4 dash muxer * misc changes: add warning in SecondaryStreamHelper.java, * strip m4a DASH files to normal m4a format (youtube only) Fix storage issues: * warn to the user if is choosing a "read only" download directory (for external SD Cards), useless is rooted :) * "write proof" allow post-processing resuming only if the device ran out of space * implement "insufficient storage" error for downloads
2019-03-23 02:54:07 +01:00
* The current network is metered (like mobile data)?
*
* @param context App context
New MP4 muxer + Queue changes + Storage fixes Main changes: * correctly check the available space (CircularFile.java) * misc cleanup (CircularFile.java) * use the "Error Reporter" for non-http errors * rewrite network state checking and add better support for API 21 (Lollipop) or higher * implement "metered networks" * add buttons in "Downloads" activity to start/pause all pending downloads, ignoring the queue flag or if the network is "metered" * add workaround for VPN connections and/or network switching. Example: switching WiFi to 3G * rewrite DataReader ¡Webm muxer is now 57% more faster! * rewrite CircularFile, use file buffers instead of memory buffers. Less troubles in low-end devices * fix missing offset for KaxCluster (WebMWriter.java), manifested as no thumbnails on file explorers Download queue: * remember queue status, unless the user pause the download (un-queue) * semi-automatic downloads, between networks. Effective if the user create a new download or the downloads activity is starts * allow enqueue failed downloads * new option, queue limit, enabled by default. Used to allow one or multiple downloads at same time Miscellaneous: * fix crash while selecting details/error menu (mistake on MissionFragment.java) * misc serialize changes (DownloadMission.java) * minor UI tweaks * allow overwrite paused downloads * fix wrong icons for grid/list button in downloads * add share option * implement #2006 * correct misspelled word in strings.xml (es) (cmn) * fix MissionAdapter crash during device shutdown New Mp4Muxer + required changes: * new mp4 muxer (from dash only) with this, muxing on Android 7 is possible now!!! * re-work in SharpStream * drop mp4 dash muxer * misc changes: add warning in SecondaryStreamHelper.java, * strip m4a DASH files to normal m4a format (youtube only) Fix storage issues: * warn to the user if is choosing a "read only" download directory (for external SD Cards), useless is rooted :) * "write proof" allow post-processing resuming only if the device ran out of space * implement "insufficient storage" error for downloads
2019-03-23 02:54:07 +01:00
* @return {@code true} if connected to a metered network
*/
Add support of other delivery methods than progressive HTTP (in the player only) Detailed changes: - External players: - Add a message instruction about stream selection; - Add a message when there is no stream available for external players; - Return now HLS, DASH and SmoothStreaming URL contents, in addition to progressive HTTP ones. - Player: - Support DASH, HLS and SmoothStreaming streams for videos, whether they are content URLs or the manifests themselves, in addition to progressive HTTP ones; - Use a custom HttpDataSource to play YouTube contents, based of ExoPlayer's default one, which allows better spoofing of official clients (custom user-agent and headers (depending of the client used), use of range and rn (set dynamically by the DataSource) parameters); - Fetch YouTube progressive contents as DASH streams, like official clients, support fully playback of livestreams which have ended recently and OTF streams; - Use ExoPlayer's default retries count for contents on non-fatal errors (instead of Integer.MAX_VALUE for non-live contents and 5 for live contents). - Download dialog: - Add message about support of progressive HTTP streams only for downloading; - Remove several duplicated code and update relevant usages; - Support downloading of contents with an unknown media format. - ListHelper: - Catch NumberFormatException when trying to compare two video streams between them. - Tests: - Update ListHelperTest and StreamItemAdapterTest to fix breaking changes in the extractor. - Other places: - Fixes deprecation of changes made in the extractor; - Improve some code related to the files changed. - Issues fixed and/or improved with the changes: - Seeking of PeerTube HLS streams (the duration shown was the one from the stream duration and not the one parsed, incomplete because HLS streams are fragmented MP4s with multiple sidx boxes, for which seeking is not supported by ExoPlayer) (the app now uses the HLS manifest returned for each quality, in the master playlist (not fetched and computed by the extractor)); - Crash when loading PeerTube streams with a separated audio; - Lack of some streams on some YouTube videos (OTF streams); - Loading times of YouTube streams, after a quality change or a playback start; - View count of YouTube ended livestreams interpreted as watching count (this type of streams is not interpreted anymore as livestreams); - Watchable time of YouTube ended livestreams; - Playback of SoundCloud HLS-only tracks (which cannot be downloaded anymore because the workaround which was used is being removed by SoundCloud, so it has been removed from the extractor).
2022-06-16 11:13:19 +02:00
public static boolean isMeteredNetwork(@NonNull final Context context) {
final ConnectivityManager manager =
ContextCompat.getSystemService(context, ConnectivityManager.class);
if (manager == null || manager.getActiveNetworkInfo() == null) {
return false;
}
New MP4 muxer + Queue changes + Storage fixes Main changes: * correctly check the available space (CircularFile.java) * misc cleanup (CircularFile.java) * use the "Error Reporter" for non-http errors * rewrite network state checking and add better support for API 21 (Lollipop) or higher * implement "metered networks" * add buttons in "Downloads" activity to start/pause all pending downloads, ignoring the queue flag or if the network is "metered" * add workaround for VPN connections and/or network switching. Example: switching WiFi to 3G * rewrite DataReader ¡Webm muxer is now 57% more faster! * rewrite CircularFile, use file buffers instead of memory buffers. Less troubles in low-end devices * fix missing offset for KaxCluster (WebMWriter.java), manifested as no thumbnails on file explorers Download queue: * remember queue status, unless the user pause the download (un-queue) * semi-automatic downloads, between networks. Effective if the user create a new download or the downloads activity is starts * allow enqueue failed downloads * new option, queue limit, enabled by default. Used to allow one or multiple downloads at same time Miscellaneous: * fix crash while selecting details/error menu (mistake on MissionFragment.java) * misc serialize changes (DownloadMission.java) * minor UI tweaks * allow overwrite paused downloads * fix wrong icons for grid/list button in downloads * add share option * implement #2006 * correct misspelled word in strings.xml (es) (cmn) * fix MissionAdapter crash during device shutdown New Mp4Muxer + required changes: * new mp4 muxer (from dash only) with this, muxing on Android 7 is possible now!!! * re-work in SharpStream * drop mp4 dash muxer * misc changes: add warning in SecondaryStreamHelper.java, * strip m4a DASH files to normal m4a format (youtube only) Fix storage issues: * warn to the user if is choosing a "read only" download directory (for external SD Cards), useless is rooted :) * "write proof" allow post-processing resuming only if the device ran out of space * implement "insufficient storage" error for downloads
2019-03-23 02:54:07 +01:00
return manager.isActiveNetworkMetered();
}
2023-03-19 23:37:52 +01:00
/**
* Get a {@link Comparator} to compare {@link AudioStream}s by their format and bitrate.
*
* <p>The preferred stream will be ordered last.</p>
*
2023-03-19 23:37:52 +01:00
* @param context app context
* @return Comparator
*/
private static Comparator<AudioStream> getAudioFormatComparator(
final @NonNull Context context) {
final MediaFormat defaultFormat = getDefaultFormat(context,
R.string.default_audio_format_key, R.string.default_audio_format_value);
return getAudioFormatComparator(defaultFormat, isLimitingDataUsage(context));
}
/**
* Get a {@link Comparator} to compare {@link AudioStream}s by their format and bitrate.
*
* <p>The preferred stream will be ordered last.</p>
*
* @param defaultFormat the default format to look for
2023-03-19 22:31:31 +01:00
* @param limitDataUsage choose low bitrate audio stream
* @return Comparator
*/
2023-03-19 23:37:52 +01:00
static Comparator<AudioStream> getAudioFormatComparator(
@Nullable final MediaFormat defaultFormat, final boolean limitDataUsage) {
final List<MediaFormat> formatRanking = limitDataUsage
? AUDIO_FORMAT_EFFICIENCY_RANKING : AUDIO_FORMAT_QUALITY_RANKING;
Comparator<AudioStream> bitrateComparator =
Comparator.comparingInt(AudioStream::getAverageBitrate);
if (limitDataUsage) {
bitrateComparator = bitrateComparator.reversed();
}
2023-03-19 23:37:52 +01:00
return Comparator.comparing(AudioStream::getFormat, (o1, o2) -> {
if (defaultFormat != null) {
return Boolean.compare(o1 == defaultFormat, o2 == defaultFormat);
}
return 0;
}).thenComparing(bitrateComparator).thenComparingInt(
stream -> formatRanking.indexOf(stream.getFormat()));
}
/**
2023-03-19 23:37:52 +01:00
* Get a {@link Comparator} to compare {@link AudioStream}s by their tracks.
*
2023-04-21 23:15:37 +02:00
* <p>Tracks will be compared this order:</p>
* <ol>
2023-04-21 23:15:37 +02:00
* <li>If {@code preferOriginalAudio}: use original audio</li>
* <li>Language matches {@code preferredLanguage}</li>
* <li>
* Track type ranks highest in this order:
* <i>Original</i> > <i>Dubbed</i> > <i>Descriptive</i>
* <p>If {@code preferDescriptiveAudio}:
* <i>Descriptive</i> > <i>Dubbed</i> > <i>Original</i></p>
* </li>
* <li>Language is English</li>
* </ol>
*
* <p>The preferred track will be ordered last.</p>
*
* @param context App context
* @return Comparator
*/
2023-03-19 23:37:52 +01:00
private static Comparator<AudioStream> getAudioTrackComparator(
@NonNull final Context context) {
final SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
2023-03-19 22:31:31 +01:00
final Locale preferredLanguage = Localization.getPreferredLocale(context);
final boolean preferOriginalAudio =
preferences.getBoolean(context.getString(R.string.prefer_original_audio_key),
false);
final boolean preferDescriptiveAudio =
preferences.getBoolean(context.getString(R.string.prefer_descriptive_audio_key),
false);
2023-03-19 23:37:52 +01:00
return getAudioTrackComparator(preferredLanguage, preferOriginalAudio,
preferDescriptiveAudio);
2023-03-19 22:31:31 +01:00
}
/**
2023-03-19 23:37:52 +01:00
* Get a {@link Comparator} to compare {@link AudioStream}s by their tracks.
*
2023-04-21 23:15:37 +02:00
* <p>Tracks will be compared this order:</p>
* <ol>
2023-04-21 23:15:37 +02:00
* <li>If {@code preferOriginalAudio}: use original audio</li>
* <li>Language matches {@code preferredLanguage}</li>
* <li>
* Track type ranks highest in this order:
* <i>Original</i> > <i>Dubbed</i> > <i>Descriptive</i>
* <p>If {@code preferDescriptiveAudio}:
* <i>Descriptive</i> > <i>Dubbed</i> > <i>Original</i></p>
* </li>
* <li>Language is English</li>
* </ol>
*
* <p>The preferred track will be ordered last.</p>
*
* @param preferredLanguage Preferred audio stream language
* @param preferOriginalAudio Get the original audio track regardless of its language
2023-03-19 22:31:31 +01:00
* @param preferDescriptiveAudio Prefer the descriptive audio track if available
* @return Comparator
*/
2023-03-19 23:37:52 +01:00
static Comparator<AudioStream> getAudioTrackComparator(
2023-05-01 00:04:04 +02:00
final Locale preferredLanguage,
final boolean preferOriginalAudio,
2023-03-19 23:37:52 +01:00
final boolean preferDescriptiveAudio) {
2023-03-19 22:31:31 +01:00
final String langCode = preferredLanguage.getISO3Language();
final List<AudioTrackType> trackTypeRanking = preferDescriptiveAudio
? AUDIO_TRACK_TYPE_RANKING_DESCRIPTIVE : AUDIO_TRACK_TYPE_RANKING;
return Comparator.comparing(AudioStream::getAudioTrackType, (o1, o2) -> {
if (preferOriginalAudio) {
return Boolean.compare(
o1 == AudioTrackType.ORIGINAL, o2 == AudioTrackType.ORIGINAL);
}
return 0;
}).thenComparing(AudioStream::getAudioLocale,
Comparator.nullsFirst(Comparator.comparing(
2023-03-19 22:31:31 +01:00
locale -> locale.getISO3Language().equals(langCode))))
.thenComparing(AudioStream::getAudioTrackType,
Comparator.nullsFirst(Comparator.comparingInt(trackTypeRanking::indexOf)))
.thenComparing(AudioStream::getAudioLocale,
Comparator.nullsFirst(Comparator.comparing(
locale -> locale.getISO3Language().equals(
2023-03-19 23:37:52 +01:00
Locale.ENGLISH.getISO3Language()))));
}
/**
* Get a {@link Comparator} to compare {@link AudioStream}s by their languages and track types
* for alphabetical sorting.
*
* @param context app context for localization
* @return Comparator
*/
private static Comparator<AudioStream> getAudioTrackNameComparator(
@NonNull final Context context) {
final Locale appLoc = Localization.getAppLocale(context);
return Comparator.comparing(AudioStream::getAudioLocale, Comparator.nullsLast(
Comparator.comparing(locale -> locale.getDisplayName(appLoc))))
.thenComparing(AudioStream::getAudioTrackType);
}
}