fix(YouTube - Disable Shorts resuming on startup): Resolve patch not working on experimental versions

Co-authored-by: ILoveOpenSourceApplications <117499019+iloveopensourceapplications@users.noreply.github.com>
This commit is contained in:
oSumAtrIX 2026-03-21 19:37:50 +01:00
parent 53318c48ee
commit 58898b92fe
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
7 changed files with 130 additions and 87 deletions

View file

@ -0,0 +1,21 @@
package app.revanced.extension.youtube.patches;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class DisableResumingShortsOnStartupPatch {
/**
* Injection point.
*/
public static boolean disableResumingShortsOnStartup() {
return Settings.DISABLE_RESUMING_SHORTS_ON_STARTUP.get();
}
/**
* Injection point.
*/
public static boolean disableResumingShortsOnStartup(boolean original) {
return original && !Settings.DISABLE_RESUMING_SHORTS_ON_STARTUP.get();
}
}

View file

@ -1,21 +0,0 @@
package app.revanced.extension.youtube.patches;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class DisableResumingStartupShortsPlayerPatch {
/**
* Injection point.
*/
public static boolean disableResumingStartupShortsPlayer() {
return Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
}
/**
* Injection point.
*/
public static boolean disableResumingStartupShortsPlayer(boolean original) {
return original && !Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
}
}

View file

@ -324,7 +324,7 @@ public class Settings extends YouTubeAndMusicSettings {
public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true); public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true);
// Shorts // Shorts
public static final BooleanSetting DISABLE_RESUMING_SHORTS_PLAYER = new BooleanSetting("revanced_disable_resuming_shorts_player", FALSE); public static final BooleanSetting DISABLE_RESUMING_SHORTS_ON_STARTUP = new BooleanSetting("revanced_disable_resuming_shorts_on_startup", FALSE);
public static final BooleanSetting DISABLE_SHORTS_BACKGROUND_PLAYBACK = new BooleanSetting("revanced_shorts_disable_background_playback", FALSE); public static final BooleanSetting DISABLE_SHORTS_BACKGROUND_PLAYBACK = new BooleanSetting("revanced_shorts_disable_background_playback", FALSE);
public static final EnumSetting<ShortsPlayerType> SHORTS_PLAYER_TYPE = new EnumSetting<>("revanced_shorts_player_type", ShortsPlayerType.SHORTS_PLAYER); public static final EnumSetting<ShortsPlayerType> SHORTS_PLAYER_TYPE = new EnumSetting<>("revanced_shorts_player_type", ShortsPlayerType.SHORTS_PLAYER);
public static final BooleanSetting HIDE_SHORTS_AI_BUTTON = new BooleanSetting("revanced_hide_shorts_ai_button", FALSE); public static final BooleanSetting HIDE_SHORTS_AI_BUTTON = new BooleanSetting("revanced_hide_shorts_ai_button", FALSE);

View file

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.startupshortsreset package app.revanced.patches.youtube.layout.shortsresuming
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction import app.revanced.patcher.extensions.getInstruction
@ -18,10 +18,11 @@ import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.RegisterRangeInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/DisableResumingStartupShortsPlayerPatch;" "Lapp/revanced/extension/youtube/patches/DisableResumingShortsOnStartupPatch;"
@Suppress("unused") @Suppress("unused")
val disableResumingShortsOnStartupPatch = bytecodePatch( val disableResumingShortsOnStartupPatch = bytecodePatch(
@ -44,24 +45,33 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
"20.37.48", "20.37.48",
"20.40.45", "20.40.45",
"20.44.38" "20.44.38"
// This patch is obsolete with 21.03 because YT seems to have
// removed resuming Shorts functionality.
// TODO: Before adding 21.03+, merge this patch into `Hide Shorts component`
), ),
) )
apply { apply {
// 21.03+ seems to no longer have resuming Shorts functionality. addResources("youtube", "layout.shortsresuming.disableResumingShortsOnStartupPatch")
if (is_21_03_or_greater) return@apply
addResources("youtube", "layout.startupshortsreset.disableResumingShortsOnStartupPatch")
PreferenceScreen.SHORTS.addPreferences( PreferenceScreen.SHORTS.addPreferences(
SwitchPreference("revanced_disable_resuming_shorts_player"), SwitchPreference("revanced_disable_resuming_shorts_on_startup"),
) )
if (is_20_03_or_greater) { if (is_21_03_or_greater) {
userWasInShortsAlternativeMethodMatch.let { userWasInShortsEvaluateMethodMatch.let {
it.method.apply {
val instruction = getInstruction<RegisterRangeInstruction>(it[0])
val zMRegister = instruction.startRegister + 2
addInstructions(
it[0],
"""
invoke-static { v$zMRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->disableResumingShortsOnStartup(Z)Z
move-result v$zMRegister
"""
)
}
}
} else if (is_20_03_or_greater) {
userWasInShortsListenerMethodMatch.let {
it.method.apply { it.method.apply {
val insertIndex = it[2] + 1 val insertIndex = it[2] + 1
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
@ -69,7 +79,7 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
addInstructions( addInstructions(
insertIndex, insertIndex,
""" """
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer(Z)Z invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingShortsOnStartup(Z)Z
move-result v$register move-result v$register
""", """,
) )
@ -87,7 +97,7 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
addInstructionsAtControlFlowLabel( addInstructionsAtControlFlowLabel(
listenableInstructionIndex, listenableInstructionIndex,
""" """
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingShortsOnStartup()Z
move-result v$freeRegister move-result v$freeRegister
if-eqz v$freeRegister, :show_startup_shorts_player if-eqz v$freeRegister, :show_startup_shorts_player
return-void return-void
@ -101,7 +111,7 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
userWasInShortsConfigMethod.addInstructions( userWasInShortsConfigMethod.addInstructions(
0, 0,
""" """
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingShortsOnStartup()Z
move-result v0 move-result v0
if-eqz v0, :show if-eqz v0, :show
const/4 v0, 0x0 const/4 v0, 0x0

View file

@ -0,0 +1,79 @@
package app.revanced.patches.youtube.layout.shortsresuming
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import kotlin.collections.all
import kotlin.collections.zip
/**
* 21.03+
*/
internal val BytecodePatchContext.userWasInShortsEvaluateMethodMatch by composingFirstMethod {
val method1ParametersPrefix = listOf("L", "Z", "Z", "L", "Z")
val method2ParametersPrefix = listOf("L", "L", "L", "L", "L", "I")
instructions(
allOf(
Opcode.INVOKE_DIRECT_RANGE(),
method {
name == "<init>" && parameterTypes.zip(method1ParametersPrefix)
.all { (a, b) -> a.startsWith(b) }
}
),
afterAtMost(
50, allOf(
Opcode.INVOKE_DIRECT_RANGE(),
method {
name == "<init>" && parameterTypes.zip(method2ParametersPrefix)
.all { (a, b) -> a.startsWith(b) }
}
)
)
)
}
/**
* 20.02+
*/
internal
val BytecodePatchContext.userWasInShortsListenerMethodMatch by composingFirstMethod {
returnType("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Ljava/lang/Object;")
instructions(
allOf(Opcode.CHECK_CAST(), type("Ljava/lang/Boolean;")),
after(method { toString() == "Ljava/lang/Boolean;->booleanValue()Z" }),
after(Opcode.MOVE_RESULT()),
// 20.40+ string was merged into another string and is a partial match.
afterAtMost(30, "ShortsStartup SetUserWasInShortsListener"(String::contains)),
)
}
/**
* Pre 20.02
*/
internal
val BytecodePatchContext.userWasInShortsLegacyMethod by gettingFirstMethodDeclaratively {
returnType("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Ljava/lang/Object;")
instructions(
"Failed to read user_was_in_shorts proto after successful warmup"(),
)
}
/**
* 18.15.40+
*/
internal
val BytecodePatchContext.userWasInShortsConfigMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
45358360L(),
)
}

View file

@ -1,46 +0,0 @@
package app.revanced.patches.youtube.layout.startupshortsreset
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* 20.02+
*/
internal val BytecodePatchContext.userWasInShortsAlternativeMethodMatch by composingFirstMethod {
returnType("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Ljava/lang/Object;")
instructions(
allOf(Opcode.CHECK_CAST(), type("Ljava/lang/Boolean;")),
after(method { toString() == "Ljava/lang/Boolean;->booleanValue()Z" }),
after(Opcode.MOVE_RESULT()),
// 20.40+ string was merged into another string and is a partial match.
afterAtMost(15, "userIsInShorts: "(String::contains)),
)
}
/**
* Pre 20.02
*/
internal val BytecodePatchContext.userWasInShortsLegacyMethod by gettingFirstMethodDeclaratively {
returnType("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameterTypes("Ljava/lang/Object;")
instructions(
"Failed to read user_was_in_shorts proto after successful warmup"(),
)
}
/**
* 18.15.40+
*/
internal val BytecodePatchContext.userWasInShortsConfigMethod by gettingFirstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
45358360L(),
)
}

View file

@ -1490,10 +1490,10 @@ If later turned off, it is recommended to clear the app data to prevent UI bugs.
Limitation: Using the back button on the toolbar may not work"</string> Limitation: Using the back button on the toolbar may not work"</string>
<string name="revanced_change_start_page_always_summary_off">Start page is changed only on app startup</string> <string name="revanced_change_start_page_always_summary_off">Start page is changed only on app startup</string>
</patch> </patch>
<patch id="layout.startupshortsreset.disableResumingShortsOnStartupPatch"> <patch id="layout.shortsresuming.disableResumingShortsOnStartupPatch">
<string name="revanced_disable_resuming_shorts_player_title">Disable resuming Shorts player</string> <string name="revanced_disable_resuming_shorts_on_startup_title">Disable resuming Shorts player</string>
<string name="revanced_disable_resuming_shorts_player_summary_on">Shorts player will not resume on app startup</string> <string name="revanced_disable_resuming_shorts_on_startup_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> <string name="revanced_disable_resuming_shorts_on_startup_summary_off">Shorts player will resume on app startup</string>
</patch> </patch>
<patch id="layout.shortsplayer.shortsPlayerTypePatch"> <patch id="layout.shortsplayer.shortsPlayerTypePatch">
<string name="revanced_shorts_player_type_title">Open Shorts with</string> <string name="revanced_shorts_player_type_title">Open Shorts with</string>