fix(youtube/remember-playback-speed): allow to not remember playback speed (#1762)

This commit is contained in:
LisoUseInAIKyrios 2023-03-20 02:00:21 +04:00 committed by GitHub
parent 4d107567e6
commit 49ec3e83f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 108 deletions

View file

@ -18,4 +18,4 @@ import app.revanced.patcher.annotation.Package
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class RememberPlaybackRateCompatibility internal annotation class RememberPlaybackSpeedCompatibility

View file

@ -2,7 +2,7 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object ChangePlaybackRateFragmentStateFingerprint : MethodFingerprint( object ChangePlaybackSpeedFragmentStateFingerprint : MethodFingerprint(
"V", "V",
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT") strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
) )

View file

@ -2,6 +2,6 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object InitializePlaybackRateValuesFingerprint : MethodFingerprint( object InitializePlaybackSpeedValuesFingerprint : MethodFingerprint(
parameters = listOf("[L", "I") parameters = listOf("[L", "I")
) )

View file

@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object OnPlaybackRateItemClickFingerprint : MethodFingerprint( object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint(
customFingerprint = { it.name == "onItemClick" }, customFingerprint = { it.name == "onItemClick" },
opcodes = listOf( opcodes = listOf(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,

View file

@ -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.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch 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.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackRateCompatibility import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackRateFragmentStateFingerprint import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackSpeedFragmentStateFingerprint
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackRateValuesFingerprint import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackRateItemClickFingerprint 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.Opcode
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@Patch @Patch
@Name("remember-playback-rate") @Name("remember-playback-speed")
@Description("Adds the ability to remember the playback rate you chose in the video playback rate flyout.") @Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class])
@RememberPlaybackRateCompatibility @RememberPlaybackSpeedCompatibility
@Version("0.0.1") @Version("0.0.1")
class RememberPlaybackRatePatch : BytecodePatch( class RememberPlaybackSpeedPatch : BytecodePatch(
listOf(ChangePlaybackRateFragmentStateFingerprint) 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 { private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR = 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 { fun MethodFingerprint.getReference(offsetFromPatternScanResultStartIndex: Int = 0) = this.result!!.let {
val referenceInstruction = it.mutableMethod val referenceInstruction = it.mutableMethod
@ -46,92 +128,13 @@ class RememberPlaybackRatePatch : BytecodePatch(
} }
fun BytecodeContext.resolveFingerprints() { fun BytecodeContext.resolveFingerprints() {
ChangePlaybackRateFragmentStateFingerprint.result?.also { ChangePlaybackSpeedFragmentStateFingerprint.result?.also {
fun MethodFingerprint.resolve() = resolve(this@resolveFingerprints, it.classDef) fun MethodFingerprint.resolve() = resolve(this@resolveFingerprints, it.classDef)
OnPlaybackRateItemClickFingerprint.resolve() OnPlaybackSpeedItemClickFingerprint.resolve()
InitializePlaybackRateValuesFingerprint.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()
}
} }

View file

@ -46,20 +46,20 @@ class VideoIdPatch : BytecodePatch(
private lateinit var insertMethod: MutableMethod 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;` * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
*/ */
fun injectCall( fun injectCall(
methodDescriptor: String methodDescriptor: String
) { ) = insertMethod.addInstructions(
insertMethod.addInstructions( // Keep injection calls in the order they're added.
// TODO: The order has been proven to not be required, so remove the logic for keeping order. // Order has been proven to be important for the same reason that order of patch execution is important
// Keep injection calls in the order they're added: // such as for the VideoInformation patch.
// Increment index. So if additional injection calls are added, those calls run after this injection call.
insertIndex++, insertIndex++,
"invoke-static {v$videoIdRegister}, $methodDescriptor" "invoke-static {v$videoIdRegister}, $methodDescriptor"
) )
} }
} }
}