feat(YouTube): Add Open Shorts in regular player patch (#4153)

This commit is contained in:
LisoUseInAIKyrios
2024-12-19 12:11:19 +04:00
committed by GitHub
parent a4db3f1df7
commit c7c5e5b2b9
18 changed files with 463 additions and 62 deletions

View File

@ -1177,6 +1177,10 @@ public final class app/revanced/patches/youtube/layout/player/background/PlayerC
}
public final class app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenKt {
public static final fun getOpenVideosFullscreen ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/layout/player/fullscreen/OpenVideosFullscreenPatchKt {
public static final fun getOpenVideosFullscreenPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
@ -1210,6 +1214,10 @@ public final class app/revanced/patches/youtube/layout/shortsautoplay/ShortsAuto
public static final fun getShortsAutoplayPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/layout/shortsplayer/OpenShortsInRegularPlayerPatchKt {
public static final fun getOpenShortsInRegularPlayerPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockPatchKt {
public static final fun getSponsorBlockPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

View File

@ -2,7 +2,7 @@ package app.revanced.patches.shared.misc.checks
import android.os.Build.*
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
@ -82,7 +82,7 @@ fun checkEnvironmentPatch(
}
}
fun invokeCheck() = mainActivityOnCreateFingerprint.method.addInstructions(
fun invokeCheck() = mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 },$EXTENSION_CLASS_DESCRIPTOR->check(Landroid/app/Activity;)V",
)

View File

@ -14,3 +14,15 @@ internal val openVideosFullscreenPortraitFingerprint = fingerprint {
OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG
}
}
/**
* Used to enable opening regular videos fullscreen.
*/
internal val openVideosFullscreenHookPatchExtensionFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Z")
parameters()
custom { methodDef, classDef ->
methodDef.name == "isFullScreenPatchIncluded" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}

View File

@ -1,46 +1,9 @@
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")
)
}
}
@Deprecated("Renamed to openVideosFullscreenPatch", ReplaceWith("openVideosFullscreenPatch"))
val openVideosFullscreen = bytecodePatch{
dependsOn(openVideosFullscreenPatch)
}

View File

@ -0,0 +1,32 @@
package app.revanced.patches.youtube.layout.player.fullscreen
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.youtube.layout.shortsplayer.openShortsInRegularPlayerPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.insertFeatureFlagBooleanOverride
internal const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/OpenVideosFullscreenHookPatch;"
/**
* Used by both [openVideosFullscreenPatch] and [openShortsInRegularPlayerPatch].
*/
internal val openVideosFullscreenHookPatch = bytecodePatch {
dependsOn(
sharedExtensionPatch,
versionCheckPatch
)
execute {
if (!is_19_46_or_greater) {
return@execute
}
openVideosFullscreenPortraitFingerprint.method.insertFeatureFlagBooleanOverride(
OPEN_VIDEOS_FULLSCREEN_PORTRAIT_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->openVideoFullscreenPortrait(Z)Z"
)
}
}

View File

@ -0,0 +1,46 @@
package app.revanced.patches.youtube.layout.player.fullscreen
import app.revanced.patcher.patch.PatchException
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.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.returnEarly
@Suppress("unused")
val openVideosFullscreenPatch = bytecodePatch(
name = "Open videos fullscreen",
description = "Adds an option to open videos in full screen portrait mode.",
) {
dependsOn(
openVideosFullscreenHookPatch,
settingsPatch,
addResourcesPatch,
versionCheckPatch
)
compatibleWith(
"com.google.android.youtube"(
"19.46.42",
)
)
execute {
if (!is_19_46_or_greater) {
throw PatchException("'Open videos fullscreen' requires 19.46.42 or greater")
}
addResources("youtube", "layout.player.fullscreen.openVideosFullscreen")
PreferenceScreen.PLAYER.addPreferences(
SwitchPreference("revanced_open_videos_fullscreen_portrait")
)
// Enable the logic for the user Setting to open regular videos fullscreen.
openVideosFullscreenHookPatchExtensionFingerprint.method.returnEarly(true)
}
}

View File

@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.shortsautoplay
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
@ -56,7 +57,7 @@ val shortsAutoplayPatch = bytecodePatch(
}
// Main activity is used to check if app is in pip mode.
mainActivityOnCreateFingerprint.method.addInstructions(
mainActivityOnCreateFingerprint.method.addInstruction(
1,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setMainActivity(Landroid/app/Activity;)V",

View File

@ -0,0 +1,56 @@
package app.revanced.patches.youtube.layout.shortsplayer
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
/**
* Purpose of this method is not clear, and it's only used to identify
* the obfuscated name of the videoId() method in PlaybackStartDescriptor.
*/
internal val playbackStartFeatureFlagFingerprint = fingerprint {
returns("Z")
parameters(
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
)
literal {
45380134L
}
}
// Pre 19.25
internal val shortsPlaybackIntentLegacyFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters(
"L",
"Ljava/util/Map;",
"J",
"Ljava/lang/String;",
"Z",
"Ljava/util/Map;"
)
strings(
// None of these strings are unique.
"com.google.android.apps.youtube.app.endpoint.flags",
"ReelWatchFragmentArgs",
"reels_fragment_descriptor"
)
}
internal val shortsPlaybackIntentFingerprint = fingerprint {
accessFlags(AccessFlags.PROTECTED, AccessFlags.FINAL)
returns("V")
parameters(
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
"Ljava/util/Map;",
"J",
"Ljava/lang/String;"
)
strings(
// None of these strings are unique.
"com.google.android.apps.youtube.app.endpoint.flags",
"ReelWatchFragmentArgs",
"reels_fragment_descriptor"
)
}

View File

@ -0,0 +1,131 @@
package app.revanced.patches.youtube.layout.shortsplayer
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
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.ListPreference
import app.revanced.patches.youtube.layout.player.fullscreen.openVideosFullscreenHookPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/OpenShortsInRegularPlayerPatch;"
@Suppress("unused")
val openShortsInRegularPlayerPatch = bytecodePatch(
name = "Open Shorts in regular player",
description = "Adds options to open Shorts in the regular video player.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
openVideosFullscreenHookPatch,
navigationBarHookPatch,
versionCheckPatch
)
compatibleWith(
"com.google.android.youtube"(
"18.38.44",
"18.49.37",
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
),
)
execute {
addResources("youtube", "layout.shortsplayer.shortsPlayerTypePatch")
PreferenceScreen.SHORTS.addPreferences(
if (is_19_46_or_greater) {
ListPreference(
key = "revanced_shorts_player_type",
summaryKey = null,
)
} else {
ListPreference(
key = "revanced_shorts_player_type",
summaryKey = null,
entriesKey = "revanced_shorts_player_type_legacy_entries",
entryValuesKey = "revanced_shorts_player_type_legacy_entry_values"
)
}
)
// Activity is used as the context to launch an Intent.
mainActivityOnCreateFingerprint.method.addInstruction(
1,
"invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->" +
"setMainActivity(Landroid/app/Activity;)V",
)
// Find the obfuscated method name for PlaybackStartDescriptor.videoId()
val playbackStartVideoIdMethodName = playbackStartFeatureFlagFingerprint.method.let {
val stringMethodIndex = it.indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"
&& reference.returnType == "Ljava/lang/String;"
}
navigate(it).to(stringMethodIndex).stop().name
}
fun extensionInstructions(playbackStartRegister: Int, freeRegister: Int) =
"""
invoke-virtual { v$playbackStartRegister }, Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;->$playbackStartVideoIdMethodName()Ljava/lang/String;
move-result-object v$freeRegister
invoke-static { v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->openShort(Ljava/lang/String;)Z
move-result v$freeRegister
if-eqz v$freeRegister, :disabled
return-void
:disabled
nop
"""
if (!is_19_25_or_greater) {
shortsPlaybackIntentLegacyFingerprint.method.apply {
val index = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.returnType ==
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"
}
val freeRegister = getInstruction<FiveRegisterInstruction>(index).registerC
val playbackStartRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA
addInstructionsWithLabels(
index + 2,
extensionInstructions(playbackStartRegister, freeRegister)
)
}
return@execute
}
shortsPlaybackIntentFingerprint.method.addInstructionsWithLabels(
0,
"""
move-object/from16 v0, p1
${extensionInstructions(0, 1)}
"""
)
}
}

View File

@ -1,6 +1,6 @@
package app.revanced.patches.youtube.misc.announcements
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
@ -41,7 +41,7 @@ val announcementsPatch = bytecodePatch(
SwitchPreference("revanced_announcements"),
)
mainActivityOnCreateFingerprint.method.addInstructions(
mainActivityOnCreateFingerprint.method.addInstruction(
// Insert index must be greater than the insert index used by GmsCoreSupport,
// as both patch the same method and GmsCore check should be first.
1,

View File

@ -1,6 +1,6 @@
package app.revanced.patches.youtube.misc.dns
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
@ -31,7 +31,7 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
execute {
addResources("youtube", "misc.dns.checkWatchHistoryDomainNameResolutionPatch")
mainActivityOnCreateFingerprint.method.addInstructions(
mainActivityOnCreateFingerprint.method.addInstruction(
// FIXME: Insert index must be greater than the insert index used by GmsCoreSupport,
// as both patch the same method and GmsCoreSupport check should be first,
// but the patch does not depend on GmsCoreSupport, so it should not be possible to enforce this

View File

@ -221,6 +221,28 @@
<item>BROWSE</item>
</string-array>
</patch>
<patch id="layout.shortsplayer.shortsPlayerTypePatch">
<string-array name="revanced_shorts_player_type_legacy_entries">
<item>@string/revanced_shorts_player_type_shorts</item>
<item>@string/revanced_shorts_player_type_regular_player</item>
</string-array>
<string-array name="revanced_shorts_player_type_legacy_entry_values">
<!-- Enum names from extension -->
<item>SHORTS_PLAYER</item>
<item>REGULAR_PLAYER</item>
</string-array>
<string-array name="revanced_shorts_player_type_entries">
<item>@string/revanced_shorts_player_type_shorts</item>
<item>@string/revanced_shorts_player_type_regular_player</item>
<item>@string/revanced_shorts_player_type_regular_player_fullscreen</item>
</string-array>
<string-array name="revanced_shorts_player_type_entry_values">
<!-- Enum names from extension -->
<item>SHORTS_PLAYER</item>
<item>REGULAR_PLAYER</item>
<item>REGULAR_PLAYER_FULLSCREEN</item>
</string-array>
</patch>
<patch id="layout.thumbnails.alternativeThumbnailsPatch">
<string-array name="revanced_alt_thumbnail_options_entries">
<item>@string/revanced_alt_thumbnail_options_entry_1</item>

View File

@ -1058,6 +1058,12 @@ If later turned off, it is recommended to clear the app data to prevent UI bugs.
<string name="revanced_disable_resuming_shorts_player_summary_on">Shorts player will not resume on app startup</string>
<string name="revanced_disable_resuming_shorts_player_summary_off">Shorts player will resume on app startup</string>
</patch>
<patch id="layout.shortsplayer.shortsPlayerTypePatch">
<string name="revanced_shorts_player_type_title">Open Shorts with</string>
<string name="revanced_shorts_player_type_shorts">Shorts player</string>
<string name="revanced_shorts_player_type_regular_player">Regular player</string>
<string name="revanced_shorts_player_type_regular_player_fullscreen">Regular player fullscreen</string>
</patch>
<patch id="layout.shortsautoplay.shortsAutoplayPatch">
<string name="revanced_shorts_autoplay_title">Autoplay Shorts</string>
<string name="revanced_shorts_autoplay_summary_on">Shorts will autoplay</string>