NewPipe-app-android/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHelper.java

508 lines
21 KiB
Java
Raw Normal View History

package org.schabi.newpipe.player.helper;
2021-10-22 12:07:25 +02:00
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ALL;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF;
import static com.google.android.exoplayer2.Player.REPEAT_MODE_ONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER;
import static org.schabi.newpipe.player.helper.PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE;
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
import static java.lang.annotation.RetentionPolicy.SOURCE;
2021-01-08 18:35:33 +01:00
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.Settings;
import android.view.accessibility.CaptioningManager;
2019-10-04 14:59:08 +02:00
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
2020-09-29 10:43:17 +02:00
import androidx.preference.PreferenceManager;
2021-01-08 18:35:33 +01:00
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player.RepeatMode;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
2021-08-28 19:41:58 +02:00
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
2021-01-08 18:35:33 +01:00
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
2021-08-28 19:41:58 +02:00
import com.google.android.exoplayer2.ui.CaptionStyleCompat;
import com.google.android.exoplayer2.util.MimeTypes;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem;
2018-12-04 18:49:57 +01:00
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
2018-12-04 18:49:57 +01:00
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
2020-09-29 10:43:17 +02:00
import org.schabi.newpipe.extractor.utils.Utils;
2021-01-08 18:35:33 +01:00
import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.ListHelper;
import java.lang.annotation.Retention;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
2021-01-08 18:35:33 +01:00
import java.util.Objects;
import java.util.Set;
2018-06-01 22:36:09 +02:00
import java.util.concurrent.TimeUnit;
public final class PlayerHelper {
private static final StringBuilder STRING_BUILDER = new StringBuilder();
private static final Formatter STRING_FORMATTER =
new Formatter(STRING_BUILDER, Locale.getDefault());
private static final NumberFormat SPEED_FORMATTER = new DecimalFormat("0.##x");
private static final NumberFormat PITCH_FORMATTER = new DecimalFormat("##%");
@Retention(SOURCE)
@IntDef({AUTOPLAY_TYPE_ALWAYS, AUTOPLAY_TYPE_WIFI,
AUTOPLAY_TYPE_NEVER})
public @interface AutoplayType {
int AUTOPLAY_TYPE_ALWAYS = 0;
int AUTOPLAY_TYPE_WIFI = 1;
int AUTOPLAY_TYPE_NEVER = 2;
}
2020-07-13 03:17:21 +02:00
2021-01-08 18:35:33 +01:00
@Retention(SOURCE)
@IntDef({MINIMIZE_ON_EXIT_MODE_NONE, MINIMIZE_ON_EXIT_MODE_BACKGROUND,
MINIMIZE_ON_EXIT_MODE_POPUP})
public @interface MinimizeMode {
int MINIMIZE_ON_EXIT_MODE_NONE = 0;
int MINIMIZE_ON_EXIT_MODE_BACKGROUND = 1;
int MINIMIZE_ON_EXIT_MODE_POPUP = 2;
}
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 PlayerHelper() {
}
////////////////////////////////////////////////////////////////////////////
// Exposed helpers
////////////////////////////////////////////////////////////////////////////
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 String getTimeString(final int milliSeconds) {
2020-08-16 10:24:58 +02:00
final int seconds = (milliSeconds % 60000) / 1000;
final int minutes = (milliSeconds % 3600000) / 60000;
final int hours = (milliSeconds % 86400000) / 3600000;
final int days = (milliSeconds % (86400000 * 7)) / 86400000;
STRING_BUILDER.setLength(0);
return (days > 0
? STRING_FORMATTER.format("%d:%02d:%02d:%02d", days, hours, minutes, seconds)
: hours > 0
? STRING_FORMATTER.format("%d:%02d:%02d", hours, minutes, seconds)
: STRING_FORMATTER.format("%02d:%02d", minutes, seconds)
).toString();
}
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 String formatSpeed(final double speed) {
return SPEED_FORMATTER.format(speed);
}
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 String formatPitch(final double pitch) {
return PITCH_FORMATTER.format(pitch);
}
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 String subtitleMimeTypesOf(@NonNull final MediaFormat format) {
switch (format) {
case VTT:
return MimeTypes.TEXT_VTT;
case TTML:
return MimeTypes.APPLICATION_TTML;
default:
throw new IllegalArgumentException("Unrecognized mime type: " + format.name());
}
}
@NonNull
public static String captionLanguageOf(@NonNull final Context context,
2018-12-04 18:49:57 +01:00
@NonNull final SubtitlesStream subtitles) {
final String displayName = subtitles.getDisplayLanguageName();
return displayName + (subtitles.isAutoGenerated()
? " (" + context.getString(R.string.caption_auto_generated) + ")" : "");
}
@NonNull
public static String captionLanguageStemOf(@NonNull final String language) {
if (!language.contains("(") || !language.contains(")")) {
return language;
}
if (language.startsWith("(")) {
// language text is right-to-left
final String[] parts = language.split("\\)");
return parts[parts.length - 1].trim();
}
return language.split("\\(")[0].trim();
}
@NonNull
public static String resizeTypeOf(@NonNull final Context context,
2021-01-08 18:35:33 +01:00
@ResizeMode final int resizeMode) {
switch (resizeMode) {
2021-01-08 18:35:33 +01:00
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
return context.getResources().getString(R.string.resize_fit);
2021-01-08 18:35:33 +01:00
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
return context.getResources().getString(R.string.resize_fill);
2021-01-08 18:35:33 +01:00
case AspectRatioFrameLayout.RESIZE_MODE_ZOOM:
return context.getResources().getString(R.string.resize_zoom);
2021-01-08 18:35:33 +01:00
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT:
case AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH:
default:
throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode);
}
}
/**
2020-05-30 17:51:23 +02:00
* Given a {@link StreamInfo} and the existing queue items,
* provide the {@link SinglePlayQueue} consisting of the next video for auto queueing.
* <p>
2020-05-30 17:51:23 +02:00
* This method detects and prevents cycles by naively checking
* if a candidate next video's url already exists in the existing items.
* </p>
* <p>
* The first item in {@link StreamInfo#getRelatedItems()} is checked first.
2020-05-30 17:51:23 +02:00
* If it is non-null and is not part of the existing items, it will be used as the next stream.
* Otherwise, a random stream with non-repeating url will be selected
* from the {@link StreamInfo#getRelatedItems()}. Non-stream items are ignored.
* </p>
*
* @param info currently playing stream
* @param existingItems existing items in the queue
* @return {@link SinglePlayQueue} with the next stream to queue
*/
@Nullable
public static PlayQueue autoQueueOf(@NonNull final StreamInfo info,
@NonNull final List<PlayQueueItem> existingItems) {
2020-05-30 17:51:23 +02:00
final Set<String> urls = new HashSet<>(existingItems.size());
for (final PlayQueueItem item : existingItems) {
urls.add(item.getUrl());
}
final List<InfoItem> relatedItems = info.getRelatedItems();
2020-09-29 10:43:17 +02:00
if (Utils.isNullOrEmpty(relatedItems)) {
return null;
}
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
if (relatedItems.get(0) instanceof StreamInfoItem
2020-05-30 17:51:23 +02:00
&& !urls.contains(relatedItems.get(0).getUrl())) {
return getAutoQueuedSinglePlayQueue((StreamInfoItem) relatedItems.get(0));
}
final List<StreamInfoItem> autoQueueItems = new ArrayList<>();
for (final InfoItem item : relatedItems) {
if (item instanceof StreamInfoItem && !urls.contains(item.getUrl())) {
autoQueueItems.add((StreamInfoItem) item);
}
}
2020-05-30 17:51:23 +02:00
Collections.shuffle(autoQueueItems);
return autoQueueItems.isEmpty()
? null : getAutoQueuedSinglePlayQueue(autoQueueItems.get(0));
}
////////////////////////////////////////////////////////////////////////////
// Settings Resolution
////////////////////////////////////////////////////////////////////////////
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
return getPreferences(context)
.getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), false);
}
public static boolean isVolumeGestureEnabled(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
return getPreferences(context)
.getBoolean(context.getString(R.string.volume_gesture_control_key), true);
}
public static boolean isBrightnessGestureEnabled(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
return getPreferences(context)
.getBoolean(context.getString(R.string.brightness_gesture_control_key), true);
}
public static boolean isStartMainPlayerFullscreenEnabled(@NonNull final Context context) {
return getPreferences(context)
.getBoolean(context.getString(R.string.start_main_player_fullscreen_key), false);
}
public static boolean isAutoQueueEnabled(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
return getPreferences(context)
.getBoolean(context.getString(R.string.auto_queue_key), false);
}
public static boolean isClearingQueueConfirmationRequired(@NonNull final Context context) {
2020-07-14 19:21:32 +02:00
return getPreferences(context)
.getBoolean(context.getString(R.string.clear_queue_confirmation_key), false);
}
@MinimizeMode
public static int getMinimizeOnExitAction(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
final String action = getPreferences(context)
2021-01-28 14:33:12 +01:00
.getString(context.getString(R.string.minimize_on_exit_key), "");
if (action.equals(context.getString(R.string.minimize_on_exit_popup_key))) {
return MINIMIZE_ON_EXIT_MODE_POPUP;
2021-01-28 14:33:12 +01:00
} else if (action.equals(context.getString(R.string.minimize_on_exit_none_key))) {
return MINIMIZE_ON_EXIT_MODE_NONE;
2021-01-28 14:33:12 +01:00
} else {
return MINIMIZE_ON_EXIT_MODE_BACKGROUND; // default
}
}
@AutoplayType
public static int getAutoplayType(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
final String type = getPreferences(context).getString(
context.getString(R.string.autoplay_key), "");
2020-06-27 05:25:50 +02:00
if (type.equals(context.getString(R.string.autoplay_always_key))) {
return AUTOPLAY_TYPE_ALWAYS;
2020-06-27 05:25:50 +02:00
} else if (type.equals(context.getString(R.string.autoplay_never_key))) {
return AUTOPLAY_TYPE_NEVER;
} else {
return AUTOPLAY_TYPE_WIFI; // default
}
}
public static boolean isAutoplayAllowedByUser(@NonNull final Context context) {
switch (PlayerHelper.getAutoplayType(context)) {
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
return false;
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
return !ListHelper.isMeteredNetwork(context);
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
default:
return true;
}
}
@NonNull
public static SeekParameters getSeekParameters(@NonNull final Context context) {
return isUsingInexactSeek(context) ? SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
}
public static long getPreferredCacheSize() {
return 64 * 1024 * 1024L;
}
public static long getPreferredFileSize() {
return 2 * 1024 * 1024L; // ExoPlayer CacheDataSink.MIN_RECOMMENDED_FRAGMENT_SIZE
}
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
2021-10-22 12:07:25 +02:00
public static ExoTrackSelection.Factory getQualitySelector() {
return new AdaptiveTrackSelection.Factory(
1000,
AdaptiveTrackSelection.DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS,
AdaptiveTrackSelection.DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS,
AdaptiveTrackSelection.DEFAULT_BANDWIDTH_FRACTION);
}
public static boolean isUsingDSP() {
return true;
}
@NonNull
public static CaptionStyleCompat getCaptionStyle(@NonNull final Context context) {
final CaptioningManager captioningManager = ContextCompat.getSystemService(context,
CaptioningManager.class);
if (captioningManager == null || !captioningManager.isEnabled()) {
return CaptionStyleCompat.DEFAULT;
}
return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle());
}
/**
* Get scaling for captions based on system font scaling.
* <p>Options:</p>
* <ul>
* <li>Very small: 0.25f</li>
* <li>Small: 0.5f</li>
* <li>Normal: 1.0f</li>
* <li>Large: 1.5f</li>
* <li>Very large: 2.0f</li>
* </ul>
*
* @param context Android app context
* @return caption scaling
*/
public static float getCaptionScale(@NonNull final Context context) {
final CaptioningManager captioningManager = ContextCompat.getSystemService(context,
CaptioningManager.class);
if (captioningManager == null || !captioningManager.isEnabled()) {
2020-06-27 05:25:50 +02:00
return 1.0f;
}
return captioningManager.getFontScale();
}
2018-06-01 22:36:09 +02:00
2021-01-08 18:35:33 +01:00
/**
* @param context the Android context
* @return the screen brightness to use. A value less than 0 (the default) means to use the
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
* preferred screen brightness
2021-01-08 18:35:33 +01:00
*/
2018-06-01 22:36:09 +02:00
public static float getScreenBrightness(@NonNull final Context context) {
2021-01-08 18:35:33 +01:00
final SharedPreferences sp = getPreferences(context);
final long timestamp =
sp.getLong(context.getString(R.string.screen_brightness_timestamp_key), 0);
// Hypothesis: 4h covers a viewing block, e.g. evening.
// External lightning conditions will change in the next
// viewing block so we fall back to the default brightness
if ((System.currentTimeMillis() - timestamp) > TimeUnit.HOURS.toMillis(4)) {
return -1;
} else {
return sp.getFloat(context.getString(R.string.screen_brightness_key), -1);
}
2018-06-01 22:36:09 +02:00
}
public static void setScreenBrightness(@NonNull final Context context,
2021-01-08 18:35:33 +01:00
final float screenBrightness) {
getPreferences(context).edit()
.putFloat(context.getString(R.string.screen_brightness_key), screenBrightness)
.putLong(context.getString(R.string.screen_brightness_timestamp_key),
System.currentTimeMillis())
.apply();
2018-06-01 22:36:09 +02:00
}
2020-07-14 19:21:32 +02:00
public static boolean globalScreenOrientationLocked(final Context context) {
// 1: Screen orientation changes using accelerometer
// 0: Screen orientation is locked
2020-06-27 05:25:50 +02:00
return android.provider.Settings.System.getInt(
context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 0;
}
public static int getProgressiveLoadIntervalBytes(@NonNull final Context context) {
final String preferredIntervalBytes = getPreferences(context).getString(
context.getString(R.string.progressive_load_interval_key),
context.getString(R.string.progressive_load_interval_default_value));
if (context.getString(R.string.progressive_load_interval_exoplayer_default_value)
.equals(preferredIntervalBytes)) {
return ProgressiveMediaSource.DEFAULT_LOADING_CHECK_INTERVAL_BYTES;
}
// Keeping the same KiB unit used by ProgressiveMediaSource
return Integer.parseInt(preferredIntervalBytes) * 1024;
}
////////////////////////////////////////////////////////////////////////////
// Private helpers
////////////////////////////////////////////////////////////////////////////
@NonNull
private static SharedPreferences getPreferences(@NonNull final Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
2021-01-08 18:35:33 +01:00
private static boolean isUsingInexactSeek(@NonNull final Context context) {
return getPreferences(context)
2021-01-08 18:35:33 +01:00
.getBoolean(context.getString(R.string.use_inexact_seek_key), false);
}
2021-01-08 18:35:33 +01:00
private static SinglePlayQueue getAutoQueuedSinglePlayQueue(
final StreamInfoItem streamInfoItem) {
final SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem);
Objects.requireNonNull(singlePlayQueue.getItem()).setAutoQueued(true);
2021-01-08 18:35:33 +01:00
return singlePlayQueue;
}
2021-01-08 18:35:33 +01:00
////////////////////////////////////////////////////////////////////////////
// Utils used by player
////////////////////////////////////////////////////////////////////////////
public static boolean isPlaybackResumeEnabled(final Player player) {
return player.getPrefs().getBoolean(
player.getContext().getString(R.string.enable_watch_history_key), true)
&& player.getPrefs().getBoolean(
player.getContext().getString(R.string.enable_playback_resume_key), true);
}
2021-01-08 18:35:33 +01:00
@RepeatMode
public static int nextRepeatMode(@RepeatMode final int repeatMode) {
switch (repeatMode) {
case REPEAT_MODE_OFF:
return REPEAT_MODE_ONE;
case REPEAT_MODE_ONE:
return REPEAT_MODE_ALL;
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
case REPEAT_MODE_ALL:
default:
2021-01-08 18:35:33 +01:00
return REPEAT_MODE_OFF;
}
}
@ResizeMode
public static int retrieveResizeModeFromPrefs(final Player player) {
return player.getPrefs().getInt(player.getContext().getString(R.string.last_resize_mode),
AspectRatioFrameLayout.RESIZE_MODE_FIT);
}
2021-01-08 18:35:33 +01:00
@SuppressLint("SwitchIntDef") // only fit, fill and zoom are supported by NewPipe
@ResizeMode
public static int nextResizeModeAndSaveToPrefs(final Player player,
@ResizeMode final int resizeMode) {
final int newResizeMode;
switch (resizeMode) {
case AspectRatioFrameLayout.RESIZE_MODE_FIT:
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FILL;
break;
case AspectRatioFrameLayout.RESIZE_MODE_FILL:
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
break;
case AspectRatioFrameLayout.RESIZE_MODE_ZOOM:
default:
newResizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT;
break;
}
// save the new resize mode so it can be restored in a future session
2021-01-08 18:35:33 +01:00
player.getPrefs().edit().putInt(
player.getContext().getString(R.string.last_resize_mode), newResizeMode).apply();
2021-01-08 18:35:33 +01:00
return newResizeMode;
}
2018-06-01 22:36:09 +02:00
2021-01-08 18:35:33 +01:00
public static PlaybackParameters retrievePlaybackParametersFromPrefs(final Player player) {
final float speed = player.getPrefs().getFloat(player.getContext().getString(
R.string.playback_speed_key), player.getPlaybackSpeed());
final float pitch = player.getPrefs().getFloat(player.getContext().getString(
R.string.playback_pitch_key), player.getPlaybackPitch());
2021-01-19 09:27:29 +01:00
return new PlaybackParameters(speed, pitch);
2018-06-01 22:36:09 +02:00
}
2021-01-08 18:35:33 +01:00
public static void savePlaybackParametersToPrefs(final Player player,
final float speed,
final float pitch,
final boolean skipSilence) {
player.getPrefs().edit()
.putFloat(player.getContext().getString(R.string.playback_speed_key), speed)
.putFloat(player.getContext().getString(R.string.playback_pitch_key), pitch)
.putBoolean(player.getContext().getString(R.string.playback_skip_silence_key),
skipSilence)
.apply();
}
public static float getMinimumVideoHeight(final float width) {
return width / (16.0f / 9.0f); // Respect the 16:9 ratio that most videos have
}
2021-01-08 18:35:33 +01:00
public static int retrieveSeekDurationFromPreferences(final Player player) {
return Integer.parseInt(Objects.requireNonNull(player.getPrefs().getString(
player.getContext().getString(R.string.seek_duration_key),
player.getContext().getString(R.string.seek_duration_default_value))));
}
}