diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/SpeedClassFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/SpeedClassFingerprint.kt new file mode 100644 index 000000000..f6631ced0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/SpeedClassFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object SpeedClassFingerprint : MethodFingerprint( + returnType = "L", + access = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf("L"), + opcodes = listOf( + Opcode.RETURN_OBJECT + ), + strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedChangedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedChangedFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedChangedFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedChangedFingerprint.kt index 091159ee1..4fc8b7a01 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedChangedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedChangedFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.video.speed.bytecode.fingerprints +package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode @@ -9,7 +9,6 @@ object VideoSpeedChangedFingerprint : MethodFingerprint( Opcode.IF_EQZ, Opcode.IF_EQZ, Opcode.IGET, - Opcode.CHECK_CAST, Opcode.IGET_OBJECT, Opcode.INVOKE_VIRTUAL ), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedParentFingerprint.kt new file mode 100644 index 000000000..fbdc117fd --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedParentFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VideoSpeedParentFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf("L", "L", "[L", "I"), + opcodes = listOf( + Opcode.ARRAY_LENGTH, + Opcode.IF_GE, + Opcode.AGET_OBJECT, + Opcode.NEW_INSTANCE + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedPatchFingerprint.kt new file mode 100644 index 000000000..18654c26a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedPatchFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object VideoSpeedPatchFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf("F"), + customFingerprint = { it.definingClass.endsWith("/VideoSpeedPatch;") && it.name == "overrideSpeed"} +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedSettingsFingerprint.kt new file mode 100644 index 000000000..a2304e910 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/fingerprints/VideoSpeedSettingsFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object VideoSpeedSettingsFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("[L", "I"), + strings = listOf("menu_item_playback_speed") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/patch/OverrideSpeedHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/patch/OverrideSpeedHookPatch.kt new file mode 100644 index 000000000..e8db9747a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/bytecode/patch/OverrideSpeedHookPatch.kt @@ -0,0 +1,149 @@ +package app.revanced.patches.youtube.misc.overridespeed.bytecode.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.* +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patcher.util.smali.toInstructions +import app.revanced.patches.shared.annotation.YouTubeCompatibility +import app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints.* +import app.revanced.patches.youtube.misc.overridespeed.resource.patch.OverrideSpeedHookResourcePatch +import app.revanced.util.integrations.Constants.VIDEO_PATH +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.immutable.ImmutableField +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodImplementation +import org.jf.dexlib2.immutable.ImmutableMethodParameter + + +@Name("override-speed-hook") +@DependsOn([OverrideSpeedHookResourcePatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class OverrideSpeedHookPatch : BytecodePatch( + listOf( + SpeedClassFingerprint, + VideoSpeedPatchFingerprint, + VideoSpeedParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + VideoSpeedParentFingerprint.result?.let { parentResult -> + val parentClassDef = parentResult.classDef + + VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let { + videoSpeedChangedResult = it + + val startIndex = it.scanResult.patternScanResult!!.startIndex + val endIndex = it.scanResult.patternScanResult!!.endIndex + + with (it.method.implementation!!.instructions) { + + val firstReference = + (elementAt(startIndex) as ReferenceInstruction).reference as FieldReference + + val secondReference = + (elementAt(endIndex - 1) as ReferenceInstruction).reference as FieldReference + + val thirdReference = + (elementAt(endIndex) as ReferenceInstruction).reference as DexBackedMethodReference + + val parentMutableClass = parentResult.mutableClass + + parentMutableClass.methods.add( + ImmutableMethod( + parentMutableClass.type, + "overrideSpeed", + listOf(ImmutableMethodParameter("F", null, null)), + "V", + AccessFlags.PUBLIC or AccessFlags.PUBLIC, + null, + null, + ImmutableMethodImplementation( + 4, """ + const/4 v0, 0x0 + cmpg-float v0, v3, v0 + if-lez v0, :cond_0 + iget-object v0, v2, ${parentClassDef.type}->${firstReference.name}:${firstReference.type} + check-cast v0, ${secondReference.definingClass} + iget-object v1, v0, ${secondReference.definingClass}->${secondReference.name}:${secondReference.type} + invoke-virtual {v1, v3}, $thirdReference + :cond_0 + return-void + """.toInstructions(), null, null + ) + ).toMutable() + ) + } + + } ?: return VideoSpeedChangedFingerprint.toErrorResult() + } ?: return VideoSpeedParentFingerprint.toErrorResult() + + + SpeedClassFingerprint.result?.let { + with (it.mutableMethod) { + val index = it.scanResult.patternScanResult!!.endIndex + val register = (implementation!!.instructions[index] as OneRegisterInstruction).registerA + SPEED_CLASS = this.returnType + replaceInstruction( + index, + "sput-object v$register, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->speedClass:$SPEED_CLASS" + ) + addInstruction( + index + 1, + "return-object v$register" + ) + } + + } ?: return SpeedClassFingerprint.toErrorResult() + + VideoSpeedPatchFingerprint.result?.let { + with (it.mutableMethod) { + it.mutableClass.staticFields.add( + ImmutableField( + definingClass, + "speedClass", + SPEED_CLASS, + AccessFlags.PUBLIC or AccessFlags.STATIC, + null, + null, + null + ).toMutable() + ) + + addInstructions( + 1, """ + sget-object v0, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->speedClass:$SPEED_CLASS + invoke-virtual {v0, p0}, $SPEED_CLASS->overrideSpeed(F)V + """ + ) + } + + } ?: return VideoSpeedPatchFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + internal companion object { + const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoSpeedPatch;" + + lateinit var videoSpeedChangedResult: MethodFingerprintResult + + private lateinit var SPEED_CLASS: String + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/resource/patch/OverrideSpeedHookResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/resource/patch/OverrideSpeedHookResourcePatch.kt new file mode 100644 index 000000000..b1a2ab89f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/overridespeed/resource/patch/OverrideSpeedHookResourcePatch.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.misc.overridespeed.resource.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.shared.annotation.YouTubeCompatibility +import app.revanced.util.resources.ResourceUtils.copyXmlNode + +@Name("override-speed-hook-resource-patch") +@YouTubeCompatibility +@Version("0.0.1") +class OverrideSpeedHookResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + * Copy arrays + */ + context.copyXmlNode("youtube/speed/host", "values/arrays.xml", "resources") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedParentFingerprint.kt deleted file mode 100644 index c97886640..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedParentFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.youtube.video.speed.bytecode.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object VideoSpeedParentFingerprint : MethodFingerprint( - returnType = "V", - strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSetterFingerprint.kt deleted file mode 100644 index 1d7644dd1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSetterFingerprint.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.youtube.video.speed.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object VideoSpeedSetterFingerprint : MethodFingerprint( - "V", - AccessFlags.PUBLIC or AccessFlags.FINAL, - listOf("[L", "I"), - listOf( - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_STATIC, - Opcode.INVOKE_VIRTUAL, - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSettingsFingerprint.kt new file mode 100644 index 000000000..a4bf12a85 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSettingsFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.video.speed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object VideoSpeedSettingsFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("[L", "I"), + strings = listOf("menu_item_playback_speed") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt index b99bb7cfd..30dc1092c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt @@ -5,112 +5,52 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patcher.util.smali.toInstructions import app.revanced.patches.shared.annotation.YouTubeCompatibility +import app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints.VideoSpeedSettingsFingerprint +import app.revanced.patches.youtube.misc.overridespeed.bytecode.patch.OverrideSpeedHookPatch import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.* import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus import app.revanced.util.integrations.Constants.VIDEO_PATH -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.FieldReference -import org.jf.dexlib2.immutable.ImmutableMethod -import org.jf.dexlib2.immutable.ImmutableMethodImplementation -import org.jf.dexlib2.immutable.ImmutableMethodParameter @Name("default-video-speed-bytecode-patch") -@DependsOn([LegacyVideoIdPatch::class]) +@DependsOn( + [ + LegacyVideoIdPatch::class, + OverrideSpeedHookPatch::class + ] +) @YouTubeCompatibility @Version("0.0.1") class VideoSpeedBytecodePatch : BytecodePatch( listOf( - VideoSpeedChangedFingerprint, - VideoSpeedParentFingerprint, - VideoSpeedSetterFingerprint + VideoSpeedSettingsFingerprint ) ) { override fun execute(context: BytecodeContext): PatchResult { - VideoSpeedParentFingerprint.result?.let { parentResult -> - val parentClassDef = parentResult.classDef + with(OverrideSpeedHookPatch.videoSpeedChangedResult) { + val index = scanResult.patternScanResult!!.endIndex + val register = + (method.implementation!!.instructions.elementAt(index) as FiveRegisterInstruction).registerD - VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let { - startIndex = it.scanResult.patternScanResult!!.startIndex - endIndex = it.scanResult.patternScanResult!!.endIndex - - with (it.method) { - val speedInstruction = implementation!!.instructions - - firstRef = - (speedInstruction.elementAt(startIndex) as ReferenceInstruction).reference as FieldReference - - secondRef = - (speedInstruction.elementAt(endIndex - 1) as ReferenceInstruction).reference as FieldReference - - thirdRef = - (speedInstruction.elementAt(endIndex) as ReferenceInstruction).reference as DexBackedMethodReference - - val register = - (speedInstruction.elementAt(endIndex) as FiveRegisterInstruction).registerD - - it.mutableMethod.addInstruction( - endIndex, - "invoke-static { v$register }, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR" + + mutableMethod.addInstruction( + index, + "invoke-static { v$register }, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR" + "->" + "userChangedSpeed(F)V" - ) - } - - } ?: return VideoSpeedChangedFingerprint.toErrorResult() - - val parentMutableClass = parentResult.mutableClass - - parentMutableClass.methods.add( - ImmutableMethod( - parentMutableClass.type, - "overrideSpeed", - listOf(ImmutableMethodParameter("F", null, null)), - "V", - AccessFlags.PRIVATE or AccessFlags.PRIVATE, - null, - null, - ImmutableMethodImplementation( - 4, """ - const/4 v0, 0x0 - cmpg-float v0, v3, v0 - if-lez v0, :cond_0 - iget-object v0, v2, ${parentClassDef.type}->${firstRef.name}:${firstRef.type} - check-cast v0, ${secondRef.definingClass} - iget-object v1, v0, ${secondRef.definingClass}->${secondRef.name}:${secondRef.type} - invoke-virtual {v1, v3}, $thirdRef - :cond_0 - return-void - """.toInstructions(), null, null - ) - ).toMutable() ) + } - } ?: return VideoSpeedParentFingerprint.toErrorResult() - - VideoSpeedSetterFingerprint.result?.let { - it.mutableMethod.addInstructions( - 0, """ - invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue()F - move-result v0 - invoke-direct {p0, v0}, ${it.classDef.type}->overrideSpeed(F)V - """, - ) - } ?: return VideoSpeedSetterFingerprint.toErrorResult() + VideoSpeedSettingsFingerprint.result?.mutableMethod?.addInstruction( + 0, + "invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->setDefaultSpeed()V" + ) ?: return VideoSpeedSettingsFingerprint.toErrorResult() LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") @@ -122,12 +62,5 @@ class VideoSpeedBytecodePatch : BytecodePatch( private companion object { const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR = "$VIDEO_PATH/VideoSpeedPatch;" - - var startIndex: Int = 0 - var endIndex: Int = 0 - - private lateinit var firstRef: FieldReference - private lateinit var secondRef: FieldReference - private lateinit var thirdRef: DexBackedMethodReference } } \ No newline at end of file