fix(YouTube Music - Spoof client): When the default client is Android Music, playback speed menu does not open

This commit is contained in:
inotia00 2025-02-10 16:25:56 +09:00
parent af447be6cc
commit 1f10fdbccd
6 changed files with 68 additions and 15 deletions

View File

@ -116,4 +116,19 @@ public class SpoofClientPatch extends BlockRequestPatch {
}
return original;
}
/**
* Injection point.
* <p>
* 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.
* <p>
* Return false to force create the playback speed menu.
*/
public static boolean forceCreatePlaybackSpeedMenuInverse(boolean original) {
if (SPOOF_CLIENT) {
return false;
}
return original;
}
}

View File

@ -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",

View File

@ -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<OneRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex,
"""
invoke-static { v$insertRegister }, $EXTENSION_CLASS_DESCRIPTOR->forceCreatePlaybackSpeedMenuInverse(Z)Z
move-result v$insertRegister
""",
)
}
// endregion
findMethodOrThrow("$PATCHES_PATH/PatchStatus;") {

View File

@ -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)
)

View File

@ -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 {

View File

@ -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
}
}