@@ -2,21 +2,32 @@ package app.revanced.patches.youtube.layout.shortsautoplay
22
33import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
44import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
5+ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
56import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
67import app.revanced.patcher.patch.bytecodePatch
8+ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
79import app.revanced.patches.all.misc.resources.addResources
810import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
911import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
1012import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
1113import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
14+ import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater
1215import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
1316import app.revanced.patches.youtube.misc.settings.PreferenceScreen
1417import app.revanced.patches.youtube.misc.settings.settingsPatch
1518import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
1619import app.revanced.util.findInstructionIndicesReversedOrThrow
1720import app.revanced.util.getReference
21+ import app.revanced.util.indexOfFirstInstructionOrThrow
22+ import com.android.tools.smali.dexlib2.AccessFlags
23+ import com.android.tools.smali.dexlib2.Opcode
24+ import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
1825import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
26+ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
27+ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
1928import com.android.tools.smali.dexlib2.iface.reference.MethodReference
29+ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
30+ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
2031
2132private const val EXTENSION_CLASS_DESCRIPTOR = " Lapp/revanced/extension/youtube/patches/ShortsAutoplayPatch;"
2233
@@ -98,5 +109,84 @@ val shortsAutoplayPatch = bytecodePatch(
98109 )
99110 }
100111 }
112+
113+ // As of YouTube 20.09, Google has removed the code for 'Autoplay' and 'Pause' from this method.
114+ // Manually restore the removed 'Autoplay' code.
115+ if (is_20_09_or_greater) {
116+ // Variable names are only a rough guess of what these methods do.
117+ val userActionMethodIndex = indexOfInitializationInstruction(reelPlaybackFingerprint.method)
118+ val userActionMethodReference = reelPlaybackFingerprint.method
119+ .getInstruction<ReferenceInstruction >(userActionMethodIndex).reference as MethodReference
120+ val reelSequenceControllerMethodIndex = reelPlaybackFingerprint.method
121+ .indexOfFirstInstructionOrThrow(userActionMethodIndex, Opcode .INVOKE_VIRTUAL )
122+ val reelSequenceControllerMethodReference = reelPlaybackFingerprint.method
123+ .getInstruction<ReferenceInstruction >(reelSequenceControllerMethodIndex).reference as MethodReference
124+
125+ reelPlaybackRepeatFingerprint.method.apply {
126+ // Find the first call modified by extension code above.
127+ val extensionReturnResultIndex = indexOfFirstInstructionOrThrow {
128+ opcode == Opcode .INVOKE_STATIC &&
129+ getReference<MethodReference >()?.definingClass == EXTENSION_CLASS_DESCRIPTOR
130+ } + 1
131+ val enumRegister = getInstruction<OneRegisterInstruction >(extensionReturnResultIndex).registerA
132+ val getReelSequenceControllerIndex = indexOfFirstInstructionOrThrow(extensionReturnResultIndex) {
133+ val reference = getReference<FieldReference >()
134+ opcode == Opcode .IGET_OBJECT &&
135+ reference?.definingClass == definingClass &&
136+ reference.type == reelSequenceControllerMethodReference.definingClass
137+ }
138+ val getReelSequenceControllerReference =
139+ getInstruction<ReferenceInstruction >(getReelSequenceControllerIndex).reference
140+
141+ // Add a helper method to avoid finding multiple free registers.
142+ // If enum is autoplay then method performs autoplay and returns null,
143+ // otherwise returns the same enum.
144+ val helperClass = definingClass
145+ val helperName = " patch_handleAutoPlay"
146+ val helperReturnType = " Ljava/lang/Enum;"
147+ val helperMethod = ImmutableMethod (
148+ helperClass,
149+ helperName,
150+ listOf (ImmutableMethodParameter (" Ljava/lang/Enum;" , null , null )),
151+ helperReturnType,
152+ AccessFlags .PRIVATE .value,
153+ null ,
154+ null ,
155+ MutableMethodImplementation (7 ),
156+ ).toMutable().apply {
157+ addInstructionsWithLabels(
158+ 0 ,
159+ """
160+ invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR ->isAutoPlay(Ljava/lang/Enum;)Z
161+ move-result v0
162+ if-eqz v0, :ignore
163+ new-instance v0, ${userActionMethodReference.definingClass}
164+ const/4 v1, 0x3
165+ const/4 v2, 0x0
166+ invoke-direct { v0, v1, v2, v2 }, $userActionMethodReference
167+ iget-object v3, p0, $getReelSequenceControllerReference
168+ invoke-virtual { v3, v0 }, $reelSequenceControllerMethodReference
169+ const/4 v4, 0x0
170+ return-object v4
171+ :ignore
172+ return-object p1
173+ """
174+ )
175+ }
176+ reelPlaybackRepeatFingerprint.classDef.methods.add(helperMethod)
177+
178+ addInstructionsWithLabels(
179+ extensionReturnResultIndex + 1 ,
180+ """
181+ invoke-direct { p0, v$enumRegister }, $helperClass ->$helperName (Ljava/lang/Enum;)$helperReturnType
182+ move-result-object v$enumRegister
183+ if-nez v$enumRegister , :ignore
184+ return-void # Autoplay was performed.
185+ :ignore
186+ nop
187+ """
188+ )
189+ }
190+ }
101191 }
102192}
0 commit comments