diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackRateCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackRateCompatibility.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt index c95ffecac..ea47d1e68 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackRateCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt @@ -18,4 +18,4 @@ import app.revanced.patcher.annotation.Package )] ) @Target(AnnotationTarget.CLASS) -internal annotation class RememberPlaybackRateCompatibility +internal annotation class RememberPlaybackSpeedCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackRateFragmentStateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackSpeedFragmentStateFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackRateFragmentStateFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackSpeedFragmentStateFingerprint.kt index 84531239e..cb1aca4f6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackRateFragmentStateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackSpeedFragmentStateFingerprint.kt @@ -2,7 +2,7 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -object ChangePlaybackRateFragmentStateFingerprint : MethodFingerprint( +object ChangePlaybackSpeedFragmentStateFingerprint : MethodFingerprint( "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/misc/video/speed/remember/fingerprint/InitializePlaybackRateValuesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackRateValuesFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt index 733a59761..140e243cb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackRateValuesFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt @@ -2,6 +2,6 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -object InitializePlaybackRateValuesFingerprint : MethodFingerprint( +object InitializePlaybackSpeedValuesFingerprint : MethodFingerprint( parameters = listOf("[L", "I") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackRateItemClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackRateItemClickFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt index 092a8832a..059d31783 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackRateItemClickFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode -object OnPlaybackRateItemClickFingerprint : MethodFingerprint( +object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint( customFingerprint = { it.name == "onItemClick" }, opcodes = listOf( Opcode.IGET_OBJECT, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackRatePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt similarity index 57% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackRatePatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt index 2021b23d8..ecd909fc0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackRatePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt @@ -18,26 +18,108 @@ 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.speed.remember.annotation.RememberPlaybackRateCompatibility -import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackRateFragmentStateFingerprint -import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackRateValuesFingerprint -import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackRateItemClickFingerprint +import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility +import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackSpeedFragmentStateFingerprint +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.ReferenceInstruction @Patch -@Name("remember-playback-rate") -@Description("Adds the ability to remember the playback rate you chose in the video playback rate flyout.") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@RememberPlaybackRateCompatibility +@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]) +@RememberPlaybackSpeedCompatibility @Version("0.0.1") -class RememberPlaybackRatePatch : BytecodePatch( - listOf(ChangePlaybackRateFragmentStateFingerprint) +class RememberPlaybackSpeedPatch : BytecodePatch( + listOf(ChangePlaybackSpeedFragmentStateFingerprint) ) { + override fun execute(context: BytecodeContext): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_remember_playback_speed_last_selected", + StringResource( + "revanced_remember_playback_speed_last_selected_title", + "Remember playback speed changes" + ), + true, + StringResource( + "revanced_remember_playback_speed_last_selected_summary_on", + "Playback speed changes apply to all videos" + ), + StringResource( + "revanced_remember_playback_speed_last_selected_summary_off", + "Playback speed changes only apply to the current video" + ) + ) + ) + + context.resolveFingerprints() + + VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V") + + // Set the remembered playback speed. + InitializePlaybackSpeedValuesFingerprint.result!!.apply { + // Infer everything necessary for setPlaybackSate() + + val playbackHandlerWrapperFieldReference = + (object : MethodFingerprint(opcodes = listOf(Opcode.IF_EQZ)) {}).apply { + OnPlaybackSpeedItemClickFingerprint.result!!.apply { + resolve( + context, + method, + classDef + ) + } + }.getReference(-1) + val playbackHandlerWrapperImplementorClassReference = OnPlaybackSpeedItemClickFingerprint + .getReference(-1) + val playbackHandlerFieldReference = OnPlaybackSpeedItemClickFingerprint + .getReference() + val setPlaybackSpeedMethodReference = OnPlaybackSpeedItemClickFingerprint + .getReference(1) + + mutableMethod.addInstructions( + 0, + """ + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getCurrentPlaybackSpeed()F + move-result v0 + # check if the playback speed is not 1.0x + const/high16 v1, 0x3f800000 # 1.0f + cmpg-float v1, v0, v1 + if-eqz v1, :do_not_override + + # invoke setPlaybackSpeed + iget-object v1, p0, $playbackHandlerWrapperFieldReference + check-cast v1, $playbackHandlerWrapperImplementorClassReference + iget-object v2, v1, $playbackHandlerFieldReference + invoke-virtual {v2, v0}, $setPlaybackSpeedMethodReference + """.trimIndent(), + listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0))) + ) + } + + // Remember the selected playback speed. + OnPlaybackSpeedItemClickFingerprint.result!!.apply { + val setPlaybackSpeedIndex = scanResult.patternScanResult!!.endIndex + val selectedPlaybackSpeedRegister = + (mutableMethod.instruction(setPlaybackSpeedIndex) as FiveRegisterInstruction).registerD + + mutableMethod.addInstruction( + setPlaybackSpeedIndex, + "invoke-static { v$selectedPlaybackSpeedRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V" + ) + } + + + return PatchResultSuccess() + } + private companion object { const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackRatePatch;" + "Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;" fun MethodFingerprint.getReference(offsetFromPatternScanResultStartIndex: Int = 0) = this.result!!.let { val referenceInstruction = it.mutableMethod @@ -46,92 +128,13 @@ class RememberPlaybackRatePatch : BytecodePatch( } fun BytecodeContext.resolveFingerprints() { - ChangePlaybackRateFragmentStateFingerprint.result?.also { + ChangePlaybackSpeedFragmentStateFingerprint.result?.also { fun MethodFingerprint.resolve() = resolve(this@resolveFingerprints, it.classDef) - OnPlaybackRateItemClickFingerprint.resolve() - InitializePlaybackRateValuesFingerprint.resolve() + OnPlaybackSpeedItemClickFingerprint.resolve() + InitializePlaybackSpeedValuesFingerprint.resolve() - } ?: throw ChangePlaybackRateFragmentStateFingerprint.toErrorResult() + } ?: throw ChangePlaybackSpeedFragmentStateFingerprint.toErrorResult() } } - - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_remember_playback_rate_last_selected", - StringResource("revanced_remember_playback_rate_last_selected_title", "Remember playback rate changes"), - true, - StringResource( - "revanced_remember_playback_rate_last_selected_summary_on", - "Playback rate changes apply to all videos" - ), - StringResource( - "revanced_remember_playback_rate_last_selected_summary_off", - "Playback rate changes only apply to the current video" - ) - ) - ) - - context.resolveFingerprints() - - // Set the remembered playback rate. - InitializePlaybackRateValuesFingerprint.result!!.apply { - // Infer everything necessary for setPlaybackRate() - - val playbackHandlerWrapperFieldReference = - (object : MethodFingerprint(opcodes = listOf(Opcode.IF_EQZ)) {}).apply { - OnPlaybackRateItemClickFingerprint.result!!.apply { - resolve( - context, - method, - classDef - ) - } - }.getReference(-1) - val playbackHandlerWrapperImplementorClassReference = OnPlaybackRateItemClickFingerprint - .getReference(-1) - val playbackHandlerFieldReference = OnPlaybackRateItemClickFingerprint - .getReference() - val setPlaybackRateMethodReference = OnPlaybackRateItemClickFingerprint - .getReference(1) - - mutableMethod.addInstructions( - 0, - """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRememberedPlaybackRate()F - move-result v0 - - # check if the playback rate is below 0 (when a playback rate was never remembered) - - const/4 v1, 0x0 - cmpg-float v1, v0, v1 - if-lez v1, :do_not_override - - # invoke setPlaybackRate - - iget-object v1, p0, $playbackHandlerWrapperFieldReference - check-cast v1, $playbackHandlerWrapperImplementorClassReference - iget-object v2, v1, $playbackHandlerFieldReference - invoke-virtual {v2, v0}, $setPlaybackRateMethodReference - """.trimIndent(), - listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0))) - ) - } - - // Remember the selected playback rate. - OnPlaybackRateItemClickFingerprint.result!!.apply { - val setPlaybackRateIndex = scanResult.patternScanResult!!.endIndex - val selectedPlaybackRateRegister = - (mutableMethod.instruction(setPlaybackRateIndex) as FiveRegisterInstruction).registerD - - mutableMethod.addInstruction( - setPlaybackRateIndex, - "invoke-static { v$selectedPlaybackRateRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->rememberPlaybackRate(F)V" - ) - } - - - return PatchResultSuccess() - } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt index 9e6d1ed9d..5227d9748 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt @@ -46,20 +46,20 @@ class VideoIdPatch : BytecodePatch( private lateinit var insertMethod: MutableMethod /** - * Adds an invoke-static instruction, called with the new id when the video changes + * Adds an invoke-static instruction, called with the new id when the video changes. + * Be aware, this can be called multiple times for the same video id. + * * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` */ fun injectCall( methodDescriptor: String - ) { - insertMethod.addInstructions( - // TODO: The order has been proven to not be required, so remove the logic for keeping order. - // Keep injection calls in the order they're added: - // Increment index. So if additional injection calls are added, those calls run after this injection call. - insertIndex++, - "invoke-static {v$videoIdRegister}, $methodDescriptor" - ) - } + ) = insertMethod.addInstructions( + // Keep injection calls in the order they're added. + // Order has been proven to be important for the same reason that order of patch execution is important + // such as for the VideoInformation patch. + insertIndex++, + "invoke-static {v$videoIdRegister}, $methodDescriptor" + ) } }