From 14fb894f398dc4ea4fd494dff1eeee19c7fd6e95 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 21 Oct 2024 02:52:48 -0400 Subject: [PATCH] feat(YouTube): Add `Shorts autoplay` patch (#719) --- .../youtube/patches/ShortsAutoplayPatch.java | 119 ++++++++++++++++++ .../youtube/patches/VersionCheckPatch.java | 1 + .../patches/theme/SeekbarColorPatch.java | 5 +- .../youtube/settings/Settings.java | 2 + .../SegmentPlaybackController.java | 5 +- 5 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/app/revanced/integrations/youtube/patches/ShortsAutoplayPatch.java diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/ShortsAutoplayPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/ShortsAutoplayPatch.java new file mode 100644 index 00000000..412cb51e --- /dev/null +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/ShortsAutoplayPatch.java @@ -0,0 +1,119 @@ +package app.revanced.integrations.youtube.patches; + +import android.app.Activity; +import android.os.Build; + +import androidx.annotation.RequiresApi; + +import java.lang.ref.WeakReference; +import java.util.Objects; + +import app.revanced.integrations.shared.Logger; +import app.revanced.integrations.youtube.settings.Settings; + +@SuppressWarnings("unused") +public class ShortsAutoplayPatch { + + private enum ShortsLoopBehavior { + UNKNOWN, + /** + * Repeat the same Short forever! + */ + REPEAT, + /** + * Play once, then advanced to the next Short. + */ + SINGLE_PLAY, + /** + * Pause playback after 1 play. + */ + END_SCREEN; + + static void setYTEnumValue(Enum ytBehavior) { + for (ShortsLoopBehavior rvBehavior : values()) { + if (ytBehavior.name().endsWith(rvBehavior.name())) { + rvBehavior.ytEnumValue = ytBehavior; + + Logger.printDebug(() -> rvBehavior + " set to YT enum: " + ytBehavior.name()); + return; + } + } + + Logger.printException(() -> "Unknown Shorts loop behavior: " + ytBehavior.name()); + } + + /** + * YouTube enum value of the obfuscated enum type. + */ + private Enum ytEnumValue; + } + + private static WeakReference mainActivityRef = new WeakReference<>(null); + + + public static void setMainActivity(Activity activity) { + mainActivityRef = new WeakReference<>(activity); + } + + /** + * @return If the app is currently in background PiP mode. + */ + @RequiresApi(api = Build.VERSION_CODES.N) + private static boolean isAppInBackgroundPiPMode() { + Activity activity = mainActivityRef.get(); + return activity != null && activity.isInPictureInPictureMode(); + } + + /** + * Injection point. + */ + public static void setYTShortsRepeatEnum(Enum ytEnum) { + try { + for (Enum ytBehavior : Objects.requireNonNull(ytEnum.getClass().getEnumConstants())) { + ShortsLoopBehavior.setYTEnumValue(ytBehavior); + } + } catch (Exception ex) { + Logger.printException(() -> "setYTShortsRepeatEnum failure", ex); + } + } + + /** + * Injection point. + */ + @RequiresApi(api = Build.VERSION_CODES.N) + public static Enum changeShortsRepeatBehavior(Enum original) { + try { + final boolean autoplay; + + if (isAppInBackgroundPiPMode()) { + if (!VersionCheckPatch.IS_19_34_OR_GREATER) { + // 19.34+ is required to set background play behavior. + Logger.printDebug(() -> "PiP Shorts not supported, using original repeat behavior"); + + return original; + } + + autoplay = Settings.SHORTS_AUTOPLAY_BACKGROUND.get(); + } else { + autoplay = Settings.SHORTS_AUTOPLAY.get(); + } + + final ShortsLoopBehavior behavior = autoplay + ? ShortsLoopBehavior.SINGLE_PLAY + : ShortsLoopBehavior.REPEAT; + + if (behavior.ytEnumValue != null) { + Logger.printDebug(() -> behavior.ytEnumValue == original + ? "Changing Shorts repeat behavior from: " + original.name() + " to: " + behavior.ytEnumValue + : "Behavior setting is same as original. Using original: " + original.name() + ); + + return behavior.ytEnumValue; + } + } catch (Exception ex) { + Logger.printException(() -> "changeShortsRepeatState failure", ex); + } + + return original; + } +} diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/VersionCheckPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/VersionCheckPatch.java index 4ede0101..d977a32f 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/VersionCheckPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/VersionCheckPatch.java @@ -7,4 +7,5 @@ public class VersionCheckPatch { public static final boolean IS_19_21_OR_GREATER = Utils.getAppVersionName().compareTo("19.21.00") >= 0; public static final boolean IS_19_26_OR_GREATER = Utils.getAppVersionName().compareTo("19.26.00") >= 0; public static final boolean IS_19_29_OR_GREATER = Utils.getAppVersionName().compareTo("19.29.00") >= 0; + public static final boolean IS_19_34_OR_GREATER = Utils.getAppVersionName().compareTo("19.34.00") >= 0; } diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/theme/SeekbarColorPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/theme/SeekbarColorPatch.java index 261af188..7303384f 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/theme/SeekbarColorPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/theme/SeekbarColorPatch.java @@ -73,10 +73,7 @@ public final class SeekbarColorPatch { } public static boolean playerSeekbarGradientEnabled(boolean original) { - if (original) { - Logger.printDebug(() -> "playerSeekbarGradientEnabled original: " + true); - if (SEEKBAR_CUSTOM_COLOR_ENABLED) return false; - } + if (SEEKBAR_CUSTOM_COLOR_ENABLED) return false; return original; } diff --git a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java index cdf05b91..e02f4820 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java +++ b/app/src/main/java/app/revanced/integrations/youtube/settings/Settings.java @@ -247,6 +247,8 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_SHORTS_SOUND_METADATA_LABEL = new BooleanSetting("revanced_hide_shorts_sound_metadata_label", FALSE); public static final BooleanSetting HIDE_SHORTS_FULL_VIDEO_LINK_LABEL = new BooleanSetting("revanced_hide_shorts_full_video_link_label", FALSE); public static final BooleanSetting HIDE_SHORTS_NAVIGATION_BAR = new BooleanSetting("revanced_hide_shorts_navigation_bar", FALSE, true); + public static final BooleanSetting SHORTS_AUTOPLAY = new BooleanSetting("revanced_shorts_autoplay", FALSE); + public static final BooleanSetting SHORTS_AUTOPLAY_BACKGROUND = new BooleanSetting("revanced_shorts_autoplay_background", TRUE); // Seekbar public static final BooleanSetting DISABLE_PRECISE_SEEKING_GESTURE = new BooleanSetting("revanced_disable_precise_seeking_gesture", TRUE); diff --git a/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java b/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java index ad02eec8..ddf4ae16 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java +++ b/app/src/main/java/app/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController.java @@ -662,10 +662,7 @@ public class SegmentPlaybackController { */ @SuppressWarnings("unused") public static void setSponsorBarThickness(int thickness) { - if (sponsorBarThickness != thickness) { - Logger.printDebug(() -> "setSponsorBarThickness: " + thickness); - sponsorBarThickness = thickness; - } + sponsorBarThickness = thickness; } /**