Skip to content

Commit

Permalink
fix(YouTube): Unable to access Autoplay next video setting inotia00…
Browse files Browse the repository at this point in the history
  • Loading branch information
inotia00 authored and YT-Advanced committed Jan 16, 2025
1 parent 45e692b commit 189f494
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,6 @@ enum class ResourceType(val value: String) {
INTEGER("integer"),
LAYOUT("layout"),
STRING("string"),
STYLE("style")
STYLE("style"),
XML("xml")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.spoof.appversion.baseSpoofAppVersionPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.fix.cairo.cairoFragmentPatch
import app.revanced.patches.youtube.utils.indexOfGetDrawableInstruction
import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_APP_VERSION
import app.revanced.patches.youtube.utils.playservice.is_18_34_or_greater
Expand All @@ -30,6 +31,10 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference

/**
* No longer needed due to [cairoFragmentPatch].
* TODO: Test sufficiently and remove the patch.
*/
private val spoofAppVersionBytecodePatch = bytecodePatch(
description = "spoofAppVersionBytecodePatch"
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package app.revanced.patches.youtube.utils.fix.cairo

import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.settingsFragmentCairo
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.util.fingerprint.methodCall
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.insertNode
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import org.w3c.dom.Element

private val cairoFragmentResourcePatch = resourcePatch(
description = "cairoFragmentResourcePatch"
) {
dependsOn(versionCheckPatch)

execute {
/**
* Cairo fragment have been widely rolled out in YouTube 19.34+.
*/
if (!is_19_34_or_greater) {
return@execute
}

/**
* The Preference key for 'Playback' is '@string/playback_key'.
* Copy the node to add the Preference 'Playback' to the legacy settings fragment.
*/
document("res/xml/settings_fragment.xml").use { document ->
val tags = document.getElementsByTagName("Preference")
List(tags.length) { tags.item(it) as Element }
.find { it.getAttribute("android:key") == "@string/auto_play_key" }
?.let { node ->
node.insertNode("Preference", node) {
for (index in 0 until node.attributes.length) {
with (node.attributes.item(index)) {
setAttribute(nodeName, nodeValue)
}
}
setAttribute("android:key", "@string/playback_key")
}
}
}

}
}

/**
* What [cairoFragmentPatch] does:
* 1. Disable Cairo fragment settings.
* 2. Fix - When spoofing the app version to 19.20 or earlier, the app crashes or the Notifications tab is inaccessible.
* 3. Fix - Preference 'Playback' is hidden.
* 4. Some settings that were in Preference 'General' are moved to Preference 'Playback'.
*/
val cairoFragmentPatch = bytecodePatch(
description = "cairoFragmentPatch"
) {
dependsOn(
cairoFragmentResourcePatch,
sharedResourceIdPatch,
versionCheckPatch
)

execute {
/**
* Cairo fragment have been widely rolled out in YouTube 19.34+.
*/
if (!is_19_34_or_greater) {
return@execute
}

// Instead of disabling all Cairo fragment configs,
// Just disable 'Load Cairo fragment xml' and 'Set style to Cairo preference'.
val cairoFragmentConfigMethodCall = cairoFragmentConfigFingerprint
.methodCall()

fun MutableMethod.disableCairoFragmentConfig() {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.toString() == cairoFragmentConfigMethodCall
} + 2
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA

addInstruction(insertIndex, "const/4 v$insertRegister, 0x0")
}

settingsFragmentSyntheticFingerprint.methodOrThrow().apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(settingsFragmentCairo)
val fragmentStyleIndex = indexOfFirstInstructionOrThrow(literalIndex) {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL_RANGE &&
reference?.returnType == "V" &&
reference.parameterTypes.firstOrNull() == "Ljava/lang/String;"
}
val fragmentStyleMethod = getWalkerMethod(fragmentStyleIndex)

arrayOf(
// Load cairo fragment xml.
this,
// Set style to cairo preference.
fragmentStyleMethod
).forEach { method ->
method.disableCairoFragmentConfig()
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,42 @@ package app.revanced.patches.youtube.utils.fix.cairo

import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.youtube.misc.backgroundplayback.backgroundPlaybackPatch
import app.revanced.patches.youtube.utils.playservice.is_19_04_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall

/**
* As of 2025, responses to [Account/Get Setting](https://youtubei.googleapis.com/youtubei/v1/account/get_setting)
* requests no longer include the Preference 'Autoplay' (YouTube 19.34+).
*
* In YouTube 19.34+, the Preference 'Playback' of the Cairo fragment replaces the Preference 'Autoplay'.
*
* Since RVX disables the Cairo fragment,
* users who have newly installed RVX 19.34+ will no longer be able to turn 'Autoplay next video' on or off in YouTube settings.
*
* As a workaround, [cairoSettingsPatch] has been replaced by [cairoFragmentPatch].
*/
@Deprecated("Use 'cairoFragmentPatch' instead.")
@Suppress("unused")
val cairoSettingsPatch = bytecodePatch(
description = "cairoSettingsPatch"
) {
dependsOn(versionCheckPatch)
dependsOn(cairoFragmentPatch)

execute {
if (!is_19_04_or_greater) {
if (true) {
return@execute
}

/**
* Cairo Fragment was added since YouTube v19.04.38.
* Cairo fragment was added since YouTube v19.04.38.
* Disable this for the following reasons:
* 1. [backgroundPlaybackPatch] does not activate the Minimized playback setting of Cairo Fragment.
* 2. Some patches implemented in RVX do not yet support Cairo Fragments.
* 2. Some patches implemented in RVX do not yet support Cairo fragments.
*
* See <a href="https://github.com/inotia00/ReVanced_Extended/issues/2099">ReVanced_Extended#2099</a>
* or <a href="https://github.com/qnblackcat/uYouPlus/issues/1468">uYouPlus#1468</a>
* for screenshots of the Cairo Fragment.
* for screenshots of the Cairo fragment.
*/
carioFragmentConfigFingerprint.injectLiteralInstructionBooleanCall(
cairoFragmentConfigFingerprint.injectLiteralInstructionBooleanCall(
CAIRO_FRAGMENT_FEATURE_FLAG,
"0x0"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package app.revanced.patches.youtube.utils.fix.cairo
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patches.youtube.utils.resourceid.settingsFragment
import app.revanced.patches.youtube.utils.resourceid.settingsFragmentCairo
import com.android.tools.smali.dexlib2.Opcode

/**
* Added in YouTube v19.04.38
Expand All @@ -12,9 +15,17 @@ import com.android.tools.smali.dexlib2.AccessFlags
*/
internal const val CAIRO_FRAGMENT_FEATURE_FLAG = 45532100L

internal val carioFragmentConfigFingerprint = legacyFingerprint(
name = "carioFragmentConfigFingerprint",
internal val cairoFragmentConfigFingerprint = legacyFingerprint(
name = "cairoFragmentConfigFingerprint",
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
literals = listOf(CAIRO_FRAGMENT_FEATURE_FLAG),
)

internal val settingsFragmentSyntheticFingerprint = legacyFingerprint(
name = "settingsFragmentSyntheticFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(Opcode.INVOKE_VIRTUAL_RANGE),
literals = listOf(settingsFragment, settingsFragmentCairo),
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import app.revanced.patches.shared.mapping.ResourceType.INTEGER
import app.revanced.patches.shared.mapping.ResourceType.LAYOUT
import app.revanced.patches.shared.mapping.ResourceType.STRING
import app.revanced.patches.shared.mapping.ResourceType.STYLE
import app.revanced.patches.shared.mapping.ResourceType.XML
import app.revanced.patches.shared.mapping.get
import app.revanced.patches.shared.mapping.resourceMappingPatch
import app.revanced.patches.shared.mapping.resourceMappings
Expand Down Expand Up @@ -190,6 +191,10 @@ var seekEasyHorizontalTouchOffsetToStartScrubbing = -1L
private set
var seekUndoEduOverlayStub = -1L
private set
var settingsFragment = -1L
private set
var settingsFragmentCairo = -1L
private set
var slidingDialogAnimation = -1L
private set
var subtitleMenuSettingsFooterInfo = -1L
Expand Down Expand Up @@ -594,6 +599,14 @@ internal val sharedResourceIdPatch = resourcePatch(
ID,
"seek_undo_edu_overlay_stub"
]
settingsFragment = resourceMappings[
XML,
"settings_fragment"
]
settingsFragmentCairo = resourceMappings[
XML,
"settings_fragment_cairo"
]
slidingDialogAnimation = resourceMappings[
STYLE,
"SlidingDialogAnimation"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import app.revanced.patches.shared.mainactivity.injectOnCreateMethodCall
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH
import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch
import app.revanced.patches.youtube.utils.fix.cairo.cairoSettingsPatch
import app.revanced.patches.youtube.utils.fix.cairo.cairoFragmentPatch
import app.revanced.patches.youtube.utils.fix.playbackspeed.playbackSpeedWhilePlayingPatch
import app.revanced.patches.youtube.utils.fix.splash.darkModeSplashScreenPatch
import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch
Expand Down Expand Up @@ -122,7 +122,7 @@ val settingsPatch = resourcePatch(

dependsOn(
settingsBytecodePatch,
cairoSettingsPatch,
cairoFragmentPatch,
darkModeSplashScreenPatch,
playbackSpeedWhilePlayingPatch,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ Note:
<string name="revanced_hide_suggested_video_end_screen_summary_on">"Suggested video end screen is hidden when autoplay is turned off.

Autoplay can be changed in YouTube settings:
Settings → Autoplay → Autoplay next video"</string>
Settings → Autoplay / Playback → Autoplay next video"</string>
<string name="revanced_hide_suggested_video_end_screen_summary_off">Suggested video end screen is shown.</string>
<string name="revanced_skip_autoplay_countdown_title">Skip autoplay countdown</string>
<string name="revanced_skip_autoplay_countdown_summary_on">If autoplay is enabled, the next video will play immediately.</string>
Expand Down

0 comments on commit 189f494

Please sign in to comment.