diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt index da2bfffb4..c60f83030 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt @@ -4,19 +4,7 @@ import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package @Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37" - ) - )] + [Package("com.google.android.youtube", arrayOf("18.08.37"))] ) @Target(AnnotationTarget.CLASS) internal annotation class SponsorBlockCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt index e82d50d5c..a73fc2060 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt @@ -29,7 +29,6 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch -import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.* @@ -41,11 +40,13 @@ import org.jf.dexlib2.iface.reference.StringReference @Patch @DependsOn( dependencies = [ - VideoInformationPatch::class, // updates video information and adds method to seek in video - VideoIdPatch::class, - PlayerControlsBytecodePatch::class, - PlayerTypeHookPatch::class, IntegrationsPatch::class, + VideoIdPatch::class, + // Required to skip segments on time. + VideoInformationPatch::class, + // Used to prevent SponsorBlock from running on Shorts because SponsorBlock does not yet support Shorts. + PlayerTypeHookPatch::class, + PlayerControlsBytecodePatch::class, SponsorBlockResourcePatch::class, ] ) @@ -75,7 +76,7 @@ class SponsorBlockBytecodePatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { /* - Hook the video time methods + * Hook the video time methods */ with(VideoInformationPatch) { videoTimeHook( @@ -85,12 +86,12 @@ class SponsorBlockBytecodePatch : BytecodePatch( } /* - Set current video id + * Set current video id */ VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") /* - Seekbar drawing + * Seekbar drawing */ val seekbarSignatureResult = SeekbarFingerprint.result!!.let { SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) } @@ -99,7 +100,7 @@ class SponsorBlockBytecodePatch : BytecodePatch( val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions /* - Get the instance of the seekbar rectangle + * Get the instance of the seekbar rectangle */ for ((index, instruction) in seekbarMethodInstructions.withIndex()) { if (instruction.opcode != Opcode.MOVE_OBJECT_FROM16) continue @@ -127,8 +128,8 @@ class SponsorBlockBytecodePatch : BytecodePatch( } /* - Set rectangle absolute left and right positions - */ + * Set rectangle absolute left and right positions + */ val drawRectangleInstructions = seekbarMethodInstructions.withIndex().filter { (_, instruction) -> instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect" }.map { (index, instruction) -> // TODO: improve code @@ -150,8 +151,8 @@ class SponsorBlockBytecodePatch : BytecodePatch( ) /* - Draw segment - */ + * Draw segment + */ val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2) val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let { it.registerC to it.registerE @@ -162,7 +163,7 @@ class SponsorBlockBytecodePatch : BytecodePatch( ) /* - Voting & Shield button + * Voting & Shield button */ val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult @@ -268,7 +269,9 @@ class SponsorBlockBytecodePatch : BytecodePatch( } ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings") - // detect end of the video has been reached + // The vote and create segment buttons automatically change their visibility when appropriate, + // but if buttons are showing when the end of the video is reached then they will not automatically hide. + // Add a hook to forcefully hide when the end of the video is reached. AutoRepeatParentFingerprint.result ?: return AutoRepeatParentFingerprint.toErrorResult() AutoRepeatFingerprint.also { it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt index aeaec2de8..d90f70008 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt @@ -4,19 +4,7 @@ import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package @Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37" - ) - )] + [Package("com.google.android.youtube", arrayOf("18.08.37"))] ) @Target(AnnotationTarget.CLASS) internal annotation class VideoInformationCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt index e92afa1c9..648f1a7e3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint +package app.revanced.patches.youtube.misc.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt index 7ae872218..77f44a9ed 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.misc.video.information.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -20,10 +21,16 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility import app.revanced.patches.youtube.misc.video.information.fingerprints.* +import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.MutableMethodImplementation +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.immutable.ImmutableMethod import org.jf.dexlib2.immutable.ImmutableMethodParameter import org.jf.dexlib2.util.MethodUtil @@ -39,6 +46,7 @@ class VideoInformationPatch : BytecodePatch( CreateVideoPlayerSeekbarFingerprint, PlayerControllerSetTimeReferenceFingerprint, VideoTimeFingerprint, + OnPlaybackSpeedItemClickFingerprint, ) ) { override fun execute(context: BytecodeContext): PatchResult { @@ -96,15 +104,15 @@ class VideoInformationPatch : BytecodePatch( } /* - Inject call for video id + * Inject call for video id */ val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V" VideoIdPatch.injectCall(videoIdMethodDescriptor) VideoIdPatch.injectCallBackgroundPlay(videoIdMethodDescriptor) /* - Set the video time method - */ + * Set the video time method + */ with(PlayerControllerSetTimeReferenceFingerprint.result!!) { timeMethod = context.toMethodWalker(method) .nextMethod(scanResult.patternScanResult!!.startIndex, true) @@ -112,7 +120,7 @@ class VideoInformationPatch : BytecodePatch( } /* - Set the high precision video time method + * Set the high precision video time method */ highPrecisionTimeMethod = (object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also { @@ -120,10 +128,31 @@ class VideoInformationPatch : BytecodePatch( }.result!!.mutableMethod /* - Hook the methods which set the time + * Hook the methods which set the time */ highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTimeHighPrecision") + + /* + * Hook the user playback speed selection + */ + OnPlaybackSpeedItemClickFingerprint.result?.apply { + speedSelectionInsertMethod = mutableMethod + speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3 + speedSelectionValueRegister = + (mutableMethod.instruction(speedSelectionInsertIndex) as FiveRegisterInstruction).registerD + + val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions + setPlaybackSpeedContainerClassFieldReference = + getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ) + setPlaybackSpeedClassFieldReference = + getReference(speedSelectionMethodInstructions, 1, Opcode.IGET) + setPlaybackSpeedMethodReference = + getReference(speedSelectionMethodInstructions, 2, Opcode.IGET) + } ?: return OnPlaybackSpeedItemClickFingerprint.toErrorResult() + + userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed") + return PatchResultSuccess() } @@ -185,5 +214,30 @@ class VideoInformationPatch : BytecodePatch( TIME(2), HIGH_PRECISION_TIME(0), } + + private fun getReference(instructions: List, offset: Int, opcode: Opcode) = + instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference + + val Instruction.reference get() = (this as ReferenceInstruction).reference.toString() + + private lateinit var speedSelectionInsertMethod: MutableMethod + private var speedSelectionInsertIndex = 0 + private var speedSelectionValueRegister = 0 + + /** + * Hook the video speed selected by the user. + */ + internal fun userSelectedPlaybackSpeedHook(targetMethodClass: String, targetMethodName: String) = + speedSelectionInsertMethod.addInstruction( + speedSelectionInsertIndex++, + "invoke-static {v$speedSelectionValueRegister}, $targetMethodClass->$targetMethodName(F)V" + ) + + /** + * Used by [RememberPlaybackSpeedPatch] + */ + internal lateinit var setPlaybackSpeedContainerClassFieldReference: String + internal lateinit var setPlaybackSpeedClassFieldReference: String + internal lateinit var setPlaybackSpeedMethodReference: String } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt index e244a298e..ead76aa8d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint +package app.revanced.patches.youtube.misc.video.speed.current.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt index ca2260853..2dfd34fa0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.annotation.Description 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.instruction import app.revanced.patcher.patch.* @@ -16,24 +15,20 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch +import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference +import app.revanced.patches.youtube.misc.video.speed.current.fingerprint.InitializePlaybackSpeedValuesFingerprint import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility -import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint -import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackSpeedItemClickFingerprint import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction -import org.jf.dexlib2.iface.instruction.Instruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction @Patch @Name("remember-playback-speed") @Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class, VideoInformationPatch::class]) @RememberPlaybackSpeedCompatibility @Version("0.0.1") class RememberPlaybackSpeedPatch : BytecodePatch( listOf( - OnPlaybackSpeedItemClickFingerprint, InitializePlaybackSpeedValuesFingerprint ) ) { @@ -59,38 +54,21 @@ class RememberPlaybackSpeedPatch : BytecodePatch( VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V") + VideoInformationPatch.userSelectedPlaybackSpeedHook( + INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed") + /* - * The following code works by hooking the method which is called when the user selects a playback speed - * to remember the last selected playback speed. - * - * It also hooks the method which is called when the playback speeds are initialized. - * Conveniently, at this point the playback speed is set to the remembered playback speed. + * Hook the code that is called when the playback speeds are initialized, and sets the playback speed */ - - - // Set the remembered playback speed. InitializePlaybackSpeedValuesFingerprint.result?.apply { // Infer everything necessary for calling the method setPlaybackSpeed(). - val instructions = OnPlaybackSpeedItemClickFingerprint.result!!.mutableMethod.implementation!!.instructions - fun getReference(offset: Int = 0, opcode: Opcode) = - instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference - - val setPlaybackSpeedContainerClassFieldReference = - getReference(-1, Opcode.IF_EQZ) - - val setPlaybackSpeedClassFieldReference = - getReference(1, Opcode.IGET) - - val setPlaybackSpeedMethodReference = - getReference(2, Opcode.IGET) - val onItemClickListenerClassFieldReference = mutableMethod.instruction(0).reference // Registers are not used at index 0, so they can be freely used. mutableMethod.addInstructions( 0, """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getCurrentPlaybackSpeed()F + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getPlaybackSpeedOverride()F move-result v0 # Check if the playback speed is not 1.0x. @@ -102,30 +80,18 @@ class RememberPlaybackSpeedPatch : BytecodePatch( iget-object v1, p0, $onItemClickListenerClassFieldReference # Get the container class field. - iget-object v1, v1, $setPlaybackSpeedContainerClassFieldReference + iget-object v1, v1, ${VideoInformationPatch.setPlaybackSpeedContainerClassFieldReference} # Get the field from its class. - iget-object v2, v1, $setPlaybackSpeedClassFieldReference + iget-object v2, v1, ${VideoInformationPatch.setPlaybackSpeedClassFieldReference} # Invoke setPlaybackSpeed on that class. - invoke-virtual {v2, v0}, $setPlaybackSpeedMethodReference + invoke-virtual {v2, v0}, ${VideoInformationPatch.setPlaybackSpeedMethodReference} """.trimIndent(), listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0))) ) } ?: return InitializePlaybackSpeedValuesFingerprint.toErrorResult() - // Remember the selected playback speed. - OnPlaybackSpeedItemClickFingerprint.result?.apply { - val setPlaybackSpeedIndex = scanResult.patternScanResult!!.startIndex - 3 - - val selectedPlaybackSpeedRegister = - (mutableMethod.instruction(setPlaybackSpeedIndex) as FiveRegisterInstruction).registerD - - mutableMethod.addInstruction( - setPlaybackSpeedIndex, - "invoke-static { v$selectedPlaybackSpeedRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V" - ) - } ?: return OnPlaybackSpeedItemClickFingerprint.toErrorResult() return PatchResultSuccess() } @@ -133,7 +99,5 @@ class RememberPlaybackSpeedPatch : BytecodePatch( private companion object { const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;" - - val Instruction.reference get() = (this as ReferenceInstruction).reference.toString() } } \ No newline at end of file