diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaybackSpeedWhilePlayingPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaybackSpeedWhilePlayingPatch.java new file mode 100644 index 0000000000..257c926446 --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/utils/PlaybackSpeedWhilePlayingPatch.java @@ -0,0 +1,26 @@ +package app.revanced.extension.youtube.patches.utils; + +import app.revanced.extension.shared.utils.Logger; +import app.revanced.extension.youtube.shared.PlayerType; + +@SuppressWarnings("unused") +public class PlaybackSpeedWhilePlayingPatch { + private static final float DEFAULT_YOUTUBE_PLAYBACK_SPEED = 1.0f; + + public static boolean playbackSpeedChanged(float playbackSpeed) { + if (playbackSpeed == DEFAULT_YOUTUBE_PLAYBACK_SPEED && + PlayerType.getCurrent().isMaximizedOrFullscreen()) { + + Logger.printDebug(() -> "Even though playback has already started and the user has not changed the playback speed, " + + "the app attempts to change the playback speed to 1.0x." + + "\nIgnore changing playback speed, as it is invalid request."); + + return true; + } + + return false; + } + +} + + diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/playbackspeed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/playbackspeed/Fingerprints.kt new file mode 100644 index 0000000000..392efbce52 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/playbackspeed/Fingerprints.kt @@ -0,0 +1,42 @@ +package app.revanced.patches.youtube.utils.fix.playbackspeed + +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversed +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.FieldReference + +/** + * This fingerprint is compatible with YouTube 17.34.36 ~ 19.50.40. + * + * This method is usually used to set the initial speed (1.0x) when playback starts from the feed. + * For some reason, in the latest YouTube, it is invoked even after the video has already started. + */ +internal val playbackSpeedInFeedsFingerprint = legacyFingerprint( + name = "playbackSpeedInFeedsFingerprint", + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.IGET, + Opcode.MUL_INT_LIT16, + Opcode.IGET_WIDE, + Opcode.CONST_WIDE_16, + Opcode.CMP_LONG, + Opcode.IF_EQZ, + Opcode.IF_LEZ, + Opcode.SUB_LONG_2ADDR, + ), + customFingerprint = { method, _ -> + indexOfGetPlaybackSpeedInstruction(method) >= 0 + } +) + +fun indexOfGetPlaybackSpeedInstruction(method: Method) = + method.indexOfFirstInstructionReversed { + opcode == Opcode.IGET && + getReference()?.type == "F" + } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/playbackspeed/PlaybackSpeedWhilePlayingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/playbackspeed/PlaybackSpeedWhilePlayingPatch.kt new file mode 100644 index 0000000000..241f724d75 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/playbackspeed/PlaybackSpeedWhilePlayingPatch.kt @@ -0,0 +1,60 @@ +package app.revanced.patches.youtube.utils.fix.playbackspeed + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH +import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch +import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch +import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater +import app.revanced.patches.youtube.utils.playservice.versionCheckPatch +import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.indexOfFirstInstructionOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction + +private const val EXTENSION_CLASS_DESCRIPTOR = + "$UTILS_PATH/PlaybackSpeedWhilePlayingPatch;" + +val playbackSpeedWhilePlayingPatch = bytecodePatch( + description = "playbackSpeedWhilePlayingPatch" +) { + dependsOn( + sharedExtensionPatch, + playerTypeHookPatch, + versionCheckPatch, + ) + + execute { + if (!is_19_34_or_greater) { + return@execute + } + + /** + * There is an issue where sometimes when you click on a comment in a video and press the back button or click on the timestamp of the comment, the playback speed will change to 1.0x. + * + * This can be reproduced on unpatched YouTube 19.34.42+ by following these steps: + * 1. After the video starts, manually change the playback speed to something other than 1.0x. + * 2. If enough time has passed since the video started, open the comments panel. + * 3. Click on a comment and press the back button, or click on the timestamp of the comment. + * 4. Sometimes the playback speed will change to 1.0x. + * + * This is an issue that Google should fix, but it is not that hard to fix, so it has been implemented in the patch. + */ + playbackSpeedInFeedsFingerprint.methodOrThrow().apply { + val freeRegister = implementation!!.registerCount - parameters.size - 2 + val playbackSpeedIndex = indexOfGetPlaybackSpeedInstruction(this) + val playbackSpeedRegister = getInstruction(playbackSpeedIndex).registerA + val jumpIndex = indexOfFirstInstructionOrThrow(playbackSpeedIndex, Opcode.RETURN_VOID) + + addInstructionsWithLabels( + playbackSpeedIndex + 1, """ + invoke-static { v$playbackSpeedRegister }, $EXTENSION_CLASS_DESCRIPTOR->playbackSpeedChanged(F)Z + move-result v$freeRegister + if-nez v$freeRegister, :do_not_change + """, ExternalLabel("do_not_change", getInstruction(jumpIndex)) + ) + } + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt index 7259a9a4d9..e1bcc7c8ca 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/settings/SettingsPatch.kt @@ -15,6 +15,7 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch import app.revanced.patches.youtube.utils.fix.cairo.cairoSettingsPatch +import app.revanced.patches.youtube.utils.fix.playbackspeed.playbackSpeedWhilePlayingPatch import app.revanced.patches.youtube.utils.fix.splash.darkModeSplashScreenPatch import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch import app.revanced.patches.youtube.utils.patch.PatchList.SETTINGS_FOR_YOUTUBE @@ -122,6 +123,7 @@ val settingsPatch = resourcePatch( settingsBytecodePatch, cairoSettingsPatch, darkModeSplashScreenPatch, + playbackSpeedWhilePlayingPatch, ) val insertPosition = stringOption(