Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(YouTube): Add Open videos fullscreen patch #4069

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.revanced.extension.youtube.patches;

import app.revanced.extension.youtube.settings.Settings;

@SuppressWarnings("unused")
public class OpenVideosFullscreen {

/**
* Injection point.
*/
public static boolean openVideoFullscreenPortrait(boolean original) {
return Settings.OPEN_VIDEOS_FULLSCREEN_PORTRAIT.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private static boolean anyEquals(int value, int... of) {
/**
* Injection point.
*/
public static boolean gradientLoadingScreenEnabled() {
public static boolean gradientLoadingScreenEnabled(boolean original) {
return GRADIENT_LOADING_SCREEN_ENABLED;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting PLAYBACK_SPEED_DIALOG_BUTTON = new BooleanSetting("revanced_playback_speed_dialog_button", FALSE);
public static final BooleanSetting PLAYER_POPUP_PANELS = new BooleanSetting("revanced_hide_player_popup_panels", FALSE);
public static final IntegerSetting PLAYER_OVERLAY_OPACITY = new IntegerSetting("revanced_player_overlay_opacity", 100, true);
public static final BooleanSetting OPEN_VIDEOS_FULLSCREEN_PORTRAIT = new BooleanSetting("revanced_open_videos_fullscreen_portrait", FALSE);
// Miniplayer
public static final EnumSetting<MiniplayerType> MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.ORIGINAL, true);
private static final Availability MINIPLAYER_ANY_MODERN = MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3, MODERN_4);
Expand Down
4 changes: 4 additions & 0 deletions patches/api/patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,10 @@ public final class app/revanced/patches/youtube/layout/player/background/PlayerC
public static final fun getPlayerControlsBackgroundPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
}

public final class app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenKt {
public static final fun getOpenVideosFullscreenPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatchKt {
public static final fun getCustomPlayerOverlayOpacityPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,14 @@ val miniplayerPatch = bytecodePatch(
),
)

fun MutableMethod.insertBooleanOverride(index: Int, methodName: String) {
fun MutableMethod.insertMiniplayerBooleanOverride(index: Int, methodName: String) {
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index,
"""
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Z)Z
move-result v$register
""",
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Z)Z
move-result v$register
"""
)
}

Expand All @@ -257,29 +257,25 @@ val miniplayerPatch = bytecodePatch(
* Adds an override to force legacy tablet miniplayer to be used or not used.
*/
fun MutableMethod.insertLegacyTabletMiniplayerOverride(index: Int) {
insertBooleanOverride(index, "getLegacyTabletMiniplayerOverride")
insertMiniplayerBooleanOverride(index, "getLegacyTabletMiniplayerOverride")
}

/**
* Adds an override to force modern miniplayer to be used or not used.
*/
fun MutableMethod.insertModernMiniplayerOverride(index: Int) {
insertBooleanOverride(index, "getModernMiniplayerOverride")
insertMiniplayerBooleanOverride(index, "getModernMiniplayerOverride")
}

fun Fingerprint.insertLiteralValueBooleanOverride(
fun Fingerprint.insertMiniplayerFeatureFlagBooleanOverride(
literal: Long,
extensionMethod: String,
) {
method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal)
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)

insertBooleanOverride(targetIndex + 1, extensionMethod)
}
}
) = method.insertFeatureFlagBooleanOverride(
literal,
"$EXTENSION_CLASS_DESCRIPTOR->$extensionMethod(Z)Z"
)

fun Fingerprint.insertLiteralValueFloatOverride(
fun Fingerprint.insertMiniplayerFeatureFlagFloatOverride(
literal: Long,
extensionMethod: String,
) {
Expand Down Expand Up @@ -370,24 +366,24 @@ val miniplayerPatch = bytecodePatch(
}

if (is_19_23_or_greater) {
miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
"enableMiniplayerDragAndDrop",
)
}

if (is_19_25_or_greater) {
miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_MODERN_FEATURE_LEGACY_KEY,
"getModernMiniplayerOverride",
)

miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_MODERN_FEATURE_KEY,
"getModernFeatureFlagsActiveOverride",
)

miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
"enableMiniplayerDoubleTapAction",
)
Expand Down Expand Up @@ -426,19 +422,19 @@ val miniplayerPatch = bytecodePatch(
}

if (is_19_36_or_greater) {
miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
"setRoundedCorners",
)
}

if (is_19_43_or_greater) {
miniplayerOnCloseHandlerFingerprint.insertLiteralValueBooleanOverride(
miniplayerOnCloseHandlerFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DISABLED_FEATURE_KEY,
"getMiniplayerOnCloseHandler"
)

miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"setHorizontalDrag",
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app.revanced.patches.youtube.layout.player.fullscreen

import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags

internal const val OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG = 45666112L

internal val openVideosFullscreenPortraitFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("L", "Lj\$/util/Optional;")
literal {
OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package app.revanced.patches.youtube.layout.player.fullscreen

import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.insertFeatureFlagBooleanOverride

private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/OpenVideosFullscreen;"

@Suppress("unused")
val openVideosFullscreenPatch = bytecodePatch(
name = "Open videos fullscreen",
description = "Adds an option to open videos in full screen portrait mode.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)

compatibleWith(
"com.google.android.youtube"(
"19.46.42",
)
)

execute {
openVideosFullscreenPortraitFingerprint.method.insertFeatureFlagBooleanOverride(
OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->openVideoFullscreenPortrait(Z)Z"
)

// Add resources and setting last, in case the user force patches an old incompatible version.

addResources("youtube", "layout.player.fullscreen.openVideosFullscreen")

PreferenceScreen.PLAYER.addPreferences(
SwitchPreference("revanced_open_videos_fullscreen_portrait")
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.insertFeatureFlagBooleanOverride
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
Expand Down Expand Up @@ -228,19 +229,10 @@ val seekbarColorPatch = bytecodePatch(

// 19.25+ changes

playerSeekbarGradientConfigFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG)
val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(resultIndex).registerA

addInstructions(
resultIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z
move-result v$register
"""
)
}
playerSeekbarGradientConfigFingerprint.method.insertFeatureFlagBooleanOverride(
PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z"
)

lithoLinearGradientFingerprint.method.addInstruction(
0,
Expand All @@ -255,19 +247,10 @@ val seekbarColorPatch = bytecodePatch(
launchScreenLayoutTypeFingerprint,
mainActivityOnCreateFingerprint
).forEach { fingerprint ->
fingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(launchScreenLayoutTypeLotteFeatureFlag)
val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(resultIndex).registerA

addInstructions(
resultIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->useLotteLaunchSplashScreen(Z)Z
move-result v$register
"""
)
}
fingerprint.method.insertFeatureFlagBooleanOverride(
launchScreenLayoutTypeLotteFeatureFlag,
"$EXTENSION_CLASS_DESCRIPTOR->useLotteLaunchSplashScreen(Z)Z"
)
}

// Hook the splash animation drawable to set the a seekbar color theme.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app.revanced.patches.youtube.layout.theme

import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
Expand All @@ -17,10 +16,7 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.forEachChildElement
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import app.revanced.util.insertFeatureFlagBooleanOverride
import org.w3c.dom.Element

private const val EXTENSION_CLASS_DESCRIPTOR =
Expand Down Expand Up @@ -212,19 +208,10 @@ val themePatch = bytecodePatch(
SwitchPreference("revanced_gradient_loading_screen"),
)

useGradientLoadingScreenFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(GRADIENT_LOADING_SCREEN_AB_CONSTANT)
val isEnabledIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val isEnabledRegister = getInstruction<OneRegisterInstruction>(isEnabledIndex).registerA

addInstructions(
isEnabledIndex + 1,
"""
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled()Z
move-result v$isEnabledRegister
""",
)
}
useGradientLoadingScreenFingerprint.method.insertFeatureFlagBooleanOverride(
GRADIENT_LOADING_SCREEN_AB_CONSTANT,
"$EXTENSION_CLASS_DESCRIPTOR->gradientLoadingScreenEnabled(Z)Z"
)

mapOf(
themeHelperLightColorFingerprint to lightThemeBackgroundColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ internal val disableCairoSettingsPatch = bytecodePatch(
* <a href="https://github.com/qnblackcat/uYouPlus/issues/1468">uYouPlus#1468</a>.
*/
cairoFragmentConfigFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(
CAIRO_CONFIG_LITERAL_VALUE,
)

val literalIndex = indexOfFirstLiteralInstructionOrThrow(CAIRO_CONFIG_LITERAL_VALUE)
val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(resultIndex).registerA

Expand Down
15 changes: 15 additions & 0 deletions patches/src/main/kotlin/app/revanced/util/BytecodeUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import app.revanced.patches.shared.misc.mapping.resourceMappings
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.iface.reference.Reference
Expand Down Expand Up @@ -402,6 +403,20 @@ fun Method.findInstructionIndicesReversedOrThrow(opcode: Opcode): List<Int> {
return instructions
}

internal fun MutableMethod.insertFeatureFlagBooleanOverride(literal: Long, extensionsMethod: String) {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal)
val index = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(index).registerA

addInstructions(
index + 1,
"""
invoke-static { v$register }, $extensionsMethod
move-result v$register
"""
)
}

/**
* Called for _all_ instructions with the given literal value.
*/
Expand Down
5 changes: 5 additions & 0 deletions patches/src/main/resources/addresources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_player_popup_panels_summary_on">Player popup panels are hidden</string>
<string name="revanced_hide_player_popup_panels_summary_off">Player popup panels are shown</string>
</patch>
<patch id="layout.player.fullscreen.openVideosFullscreen">
<string name="revanced_open_videos_fullscreen_portrait_title">Open videos in fullscreen portrait</string>
<string name="revanced_open_videos_fullscreen_portrait_summary_on">Videos open fullscreen</string>
<string name="revanced_open_videos_fullscreen_portrait_summary_off">Videos do not open fullscreen</string>
</patch>
<patch id="layout.player.overlay.customPlayerOverlayOpacityResourcePatch">
<string name="revanced_player_overlay_opacity_title">Player overlay opacity</string>
<string name="revanced_player_overlay_opacity_summary">Opacity value between 0-100, where 0 is transparent</string>
Expand Down
Loading