diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedArrayGeneratorFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedArrayGeneratorFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedArrayGeneratorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedArrayGeneratorFingerprint.kt index abb8064b7..c8ed114c5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedArrayGeneratorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedArrayGeneratorFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.video.customspeed.fingerprints +package app.revanced.patches.shared.fingerprints.customspeed import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedLimiterFallBackFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedLimiterFallBackFingerprint.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedLimiterFallBackFingerprint.kt rename to src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedLimiterFallBackFingerprint.kt index 538ee68d0..fe42284d1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedLimiterFallBackFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedLimiterFallBackFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.video.customspeed.fingerprints +package app.revanced.patches.shared.fingerprints.customspeed import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint @@ -11,10 +11,8 @@ object SpeedLimiterFallBackFingerprint : MethodFingerprint( parameters = listOf("L"), opcodes = listOf( Opcode.CONST_HIGH16, - Opcode.GOTO, Opcode.CONST_HIGH16, - Opcode.CONST_HIGH16, - Opcode.INVOKE_STATIC, + Opcode.INVOKE_STATIC ), strings = listOf("Playback rate: %f") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedLimiterFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedLimiterFingerprint.kt similarity index 71% rename from src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedLimiterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedLimiterFingerprint.kt index 9753774a9..036b449e7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/fingerprints/SpeedLimiterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/customspeed/SpeedLimiterFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.video.customspeed.fingerprints +package app.revanced.patches.shared.fingerprints.customspeed import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint @@ -10,11 +10,6 @@ object SpeedLimiterFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("F"), opcodes = listOf( - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.CONST_HIGH16, - Opcode.GOTO, Opcode.CONST_HIGH16, Opcode.CONST_HIGH16, Opcode.INVOKE_STATIC, diff --git a/src/main/kotlin/app/revanced/patches/shared/patch/customspeed/AbstractCustomPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/shared/patch/customspeed/AbstractCustomPlaybackSpeedPatch.kt new file mode 100644 index 000000000..361f04010 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/patch/customspeed/AbstractCustomPlaybackSpeedPatch.kt @@ -0,0 +1,116 @@ +package app.revanced.patches.shared.patch.customspeed + +import app.revanced.extensions.exception +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patches.shared.fingerprints.customspeed.SpeedArrayGeneratorFingerprint +import app.revanced.patches.shared.fingerprints.customspeed.SpeedLimiterFallBackFingerprint +import app.revanced.patches.shared.fingerprints.customspeed.SpeedLimiterFingerprint +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +abstract class AbstractCustomPlaybackSpeedPatch( + private val descriptor: String, + private val maxSpeed: Float +) : BytecodePatch( + listOf( + SpeedArrayGeneratorFingerprint, + SpeedLimiterFallBackFingerprint + ) +) { + override fun execute(context: BytecodeContext) { + SpeedArrayGeneratorFingerprint.result?.let { result -> + result.mutableMethod.apply { + val targetIndex = result.scanResult.patternScanResult!!.startIndex + val targetRegister = getInstruction(targetIndex).registerA + + addInstructions( + targetIndex + 1, """ + invoke-static {v$targetRegister}, $descriptor->getLength(I)I + move-result v$targetRegister + """ + ) + + val targetInstruction = implementation!!.instructions + + for ((index, instruction) in targetInstruction.withIndex()) { + if (instruction.opcode != Opcode.INVOKE_INTERFACE) continue + + val sizeInstruction = getInstruction(index) + if ((sizeInstruction.reference as MethodReference).name != "size") continue + + val register = getInstruction(index + 1).registerA + + addInstructions( + index + 2, """ + invoke-static {v$register}, $descriptor->getSize(I)I + move-result v$register + """ + ) + break + } + + + for ((index, instruction) in targetInstruction.withIndex()) { + if (instruction.opcode != Opcode.SGET_OBJECT) continue + + val targetReference = + getInstruction(index).reference.toString() + + if (targetReference.endsWith(":[F")) { + val register = getInstruction(index).registerA + + addInstructions( + index + 1, """ + invoke-static {v$register}, $descriptor->getArray([F)[F + move-result-object v$register + """ + ) + break + } + } + } + } ?: throw SpeedArrayGeneratorFingerprint.exception + + val speedLimiterParentResult = SpeedLimiterFallBackFingerprint.result + ?: throw SpeedLimiterFallBackFingerprint.exception + SpeedLimiterFingerprint.resolve(context, speedLimiterParentResult.classDef) + val speedLimiterResult = SpeedLimiterFingerprint.result + ?: throw SpeedLimiterFingerprint.exception + + arrayOf( + speedLimiterParentResult, + speedLimiterResult + ).forEach { result -> + result.mutableMethod.apply { + val limiterMinConstIndex = + implementation!!.instructions.indexOfFirst { (it as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } + val limiterMaxConstIndex = + implementation!!.instructions.indexOfFirst { (it as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() } + + val limiterMinConstDestination = + getInstruction(limiterMinConstIndex).registerA + val limiterMaxConstDestination = + getInstruction(limiterMaxConstIndex).registerA + + replaceInstruction( + limiterMinConstIndex, + "const/high16 v$limiterMinConstDestination, 0x0" + ) + replaceInstruction( + limiterMaxConstIndex, + "const/high16 v$limiterMaxConstDestination, ${maxSpeed.toRawBits()}" + ) + } + } + + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/patch/CustomPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/patch/CustomPlaybackSpeedPatch.kt index 8f5bb685f..131e33301 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/patch/CustomPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/patch/CustomPlaybackSpeedPatch.kt @@ -1,28 +1,15 @@ package app.revanced.patches.youtube.video.customspeed.patch -import app.revanced.extensions.exception import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.shared.patch.customspeed.AbstractCustomPlaybackSpeedPatch import app.revanced.patches.youtube.flyoutpanel.oldspeedlayout.patch.OldSpeedLayoutPatch import app.revanced.patches.youtube.utils.annotations.YouTubeCompatibility import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch -import app.revanced.patches.youtube.video.customspeed.fingerprints.SpeedArrayGeneratorFingerprint -import app.revanced.patches.youtube.video.customspeed.fingerprints.SpeedLimiterFallBackFingerprint -import app.revanced.patches.youtube.video.customspeed.fingerprints.SpeedLimiterFingerprint import app.revanced.util.integrations.Constants.VIDEO_PATH -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c -import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch @Name("Custom playback speed") @@ -34,94 +21,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference ] ) @YouTubeCompatibility -class CustomPlaybackSpeedPatch : BytecodePatch( - listOf( - SpeedArrayGeneratorFingerprint, - SpeedLimiterFallBackFingerprint, - SpeedLimiterFingerprint - ) +class CustomPlaybackSpeedPatch : AbstractCustomPlaybackSpeedPatch( + "$VIDEO_PATH/CustomPlaybackSpeedPatch;", + 10.0f ) { override fun execute(context: BytecodeContext) { - SpeedArrayGeneratorFingerprint.result?.let { result -> - result.mutableMethod.apply { - val targetIndex = result.scanResult.patternScanResult!!.startIndex - val targetRegister = getInstruction(targetIndex).registerA - - addInstructions( - targetIndex + 1, """ - invoke-static {v$targetRegister}, $VIDEO_PATH/CustomPlaybackSpeedPatch;->getLength(I)I - move-result v$targetRegister - """ - ) - - val targetInstruction = implementation!!.instructions - - for ((index, instruction) in targetInstruction.withIndex()) { - if (instruction.opcode != Opcode.INVOKE_INTERFACE) continue - - val sizeInstruction = getInstruction(index) - if ((sizeInstruction.reference as MethodReference).name != "size") continue - - val register = getInstruction(index + 1).registerA - - addInstructions( - index + 2, """ - invoke-static {v$register}, $VIDEO_PATH/CustomPlaybackSpeedPatch;->getSize(I)I - move-result v$register - """ - ) - break - } - - - for ((index, instruction) in targetInstruction.withIndex()) { - if (instruction.opcode != Opcode.SGET_OBJECT) continue - - val targetReference = - getInstruction(index).reference.toString() - - if (targetReference.contains("PlayerConfigModel;") && targetReference.endsWith("[F")) { - val register = getInstruction(index).registerA - - addInstructions( - index + 1, """ - invoke-static {v$register}, $VIDEO_PATH/CustomPlaybackSpeedPatch;->getArray([F)[F - move-result-object v$register - """ - ) - break - } - } - } - } ?: throw SpeedArrayGeneratorFingerprint.exception - - arrayOf( - SpeedLimiterFallBackFingerprint, - SpeedLimiterFingerprint - ).forEach { fingerprint -> - fingerprint.result?.let { result -> - result.mutableMethod.apply { - val limiterMinConstIndex = - implementation!!.instructions.indexOfFirst { (it as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } - val limiterMaxConstIndex = - implementation!!.instructions.indexOfFirst { (it as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() } - - val limiterMinConstDestination = - getInstruction(limiterMinConstIndex).registerA - val limiterMaxConstDestination = - getInstruction(limiterMaxConstIndex).registerA - - replaceInstruction( - limiterMinConstIndex, - "const/high16 v$limiterMinConstDestination, 0x0" - ) - replaceInstruction( - limiterMaxConstIndex, - "const/high16 v$limiterMaxConstDestination, 0x41200000 # 10.0f" - ) - } - } ?: throw fingerprint.exception - } + super.execute(context) /** * Add settings @@ -134,6 +39,5 @@ class CustomPlaybackSpeedPatch : BytecodePatch( ) SettingsPatch.updatePatchStatus("custom-playback-speed") - } }