diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofClientPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofClientPatch.java index 675068ffd..12fe6d571 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofClientPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofClientPatch.java @@ -116,4 +116,19 @@ public class SpoofClientPatch extends BlockRequestPatch { } return original; } + + /** + * Injection point. + *

+ * When spoofing the client to Android, the playback speed menu is missing from the player response. + * This fix is required because playback speed is not available in YouTube Music Podcasts. + *

+ * Return false to force create the playback speed menu. + */ + public static boolean forceCreatePlaybackSpeedMenuInverse(boolean original) { + if (SPOOF_CLIENT) { + return false; + } + return original; + } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/Fingerprints.kt index 2bbf58903..6a66410c5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/Fingerprints.kt @@ -1,5 +1,6 @@ package app.revanced.patches.music.utils +import app.revanced.patches.music.utils.resourceid.varispeedUnavailableTitle import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags @@ -22,6 +23,14 @@ internal val playbackSpeedBottomSheetFingerprint = legacyFingerprint( strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT") ) +internal val playbackRateBottomSheetClassFingerprint = legacyFingerprint( + name = "playbackRateBottomSheetClassFingerprint", + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = emptyList(), + literals = listOf(varispeedUnavailableTitle) +) + internal val playbackSpeedFingerprint = legacyFingerprint( name = "playbackSpeedFingerprint", returnType = "V", diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt index f689c5dc5..712812ca1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt @@ -9,8 +9,12 @@ import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE +import app.revanced.patches.music.utils.extension.Constants.VIDEO_PATH import app.revanced.patches.music.utils.patch.PatchList.SPOOF_CLIENT +import app.revanced.patches.music.utils.playbackRateBottomSheetClassFingerprint import app.revanced.patches.music.utils.playbackSpeedBottomSheetFingerprint +import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch +import app.revanced.patches.music.utils.resourceid.varispeedUnavailableTitle import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus import app.revanced.patches.music.utils.settings.addPreferenceWithIntent @@ -18,6 +22,7 @@ import app.revanced.patches.music.utils.settings.addSwitchPreference import app.revanced.patches.music.utils.settings.settingsPatch import app.revanced.patches.shared.spoof.blockrequest.blockRequestPatch import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint +import app.revanced.patches.shared.customspeed.customPlaybackSpeedPatch import app.revanced.patches.shared.extension.Constants.PATCHES_PATH import app.revanced.patches.shared.extension.Constants.SPOOF_PATH import app.revanced.patches.shared.indexOfBrandInstruction @@ -32,6 +37,7 @@ import app.revanced.util.getReference import app.revanced.util.getWalkerMethod import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow +import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -61,7 +67,12 @@ val spoofClientPatch = bytecodePatch( dependsOn( settingsPatch, + sharedResourceIdPatch, blockRequestPatch, + customPlaybackSpeedPatch( + "$VIDEO_PATH/CustomPlaybackSpeedPatch;", + 5.0f + ), ) execute { @@ -267,6 +278,7 @@ val spoofClientPatch = bytecodePatch( // region fix for playback speed menu is not available in Podcasts + // for iOS Music playbackSpeedBottomSheetFingerprint.mutableClassOrThrow().let { val onItemClickMethod = it.methods.find { method -> method.name == "onItemClick" } @@ -302,6 +314,24 @@ val spoofClientPatch = bytecodePatch( } } + // for Android Music + playbackRateBottomSheetClassFingerprint.methodOrThrow().apply { + val literalIndex = + indexOfFirstLiteralInstructionOrThrow(varispeedUnavailableTitle) + val insertIndex = + indexOfFirstInstructionReversedOrThrow(literalIndex, Opcode.IF_EQZ) + val insertRegister = + getInstruction(insertIndex).registerA + + addInstructions( + insertIndex, + """ + invoke-static { v$insertRegister }, $EXTENSION_CLASS_DESCRIPTOR->forceCreatePlaybackSpeedMenuInverse(Z)Z + move-result v$insertRegister + """, + ) + } + // endregion findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/Fingerprints.kt deleted file mode 100644 index 17366b163..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/Fingerprints.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.music.utils.flyoutmenu - -import app.revanced.patches.music.utils.resourceid.varispeedUnavailableTitle -import app.revanced.util.fingerprint.legacyFingerprint -import app.revanced.util.or -import com.android.tools.smali.dexlib2.AccessFlags - -internal val playbackRateBottomSheetClassFingerprint = legacyFingerprint( - name = "playbackRateBottomSheetClassFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = emptyList(), - literals = listOf(varispeedUnavailableTitle) -) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/FlyoutMenuHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/FlyoutMenuHookPatch.kt index c2d7b0c8f..4a175811c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/FlyoutMenuHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/flyoutmenu/FlyoutMenuHookPatch.kt @@ -2,6 +2,8 @@ package app.revanced.patches.music.utils.flyoutmenu import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.music.utils.extension.Constants.EXTENSION_PATH +import app.revanced.patches.music.utils.extension.sharedExtensionPatch +import app.revanced.patches.music.utils.playbackRateBottomSheetClassFingerprint import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch import app.revanced.util.addStaticFieldToExtension import app.revanced.util.fingerprint.methodOrThrow @@ -12,7 +14,10 @@ private const val EXTENSION_VIDEO_UTILS_CLASS_DESCRIPTOR = val flyoutMenuHookPatch = bytecodePatch( description = "flyoutMenuHookPatch", ) { - dependsOn(sharedResourceIdPatch) + dependsOn( + sharedExtensionPatch, + sharedResourceIdPatch, + ) execute { diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/customspeed/CustomPlaybackSpeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/customspeed/CustomPlaybackSpeedPatch.kt index c23316358..42cb1f3ca 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/customspeed/CustomPlaybackSpeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/customspeed/CustomPlaybackSpeedPatch.kt @@ -14,6 +14,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference +private var patchIncluded = false + fun customPlaybackSpeedPatch( descriptor: String, maxSpeed: Float @@ -21,6 +23,10 @@ fun customPlaybackSpeedPatch( description = "customPlaybackSpeedPatch" ) { execute { + if (patchIncluded) { + return@execute + } + arrayGeneratorFingerprint.matchOrThrow().let { it.method.apply { val targetIndex = it.patternMatch!!.startIndex @@ -85,6 +91,8 @@ fun customPlaybackSpeedPatch( } } + patchIncluded = true + } }