diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt index bb6dd617b..53f172356 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt @@ -8,7 +8,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.PatchException -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint @@ -16,7 +15,6 @@ import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModel import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackPatch import app.revanced.patches.youtube.utils.compatibility.Constants import app.revanced.patches.youtube.utils.fingerprints.PlaybackRateBottomSheetBuilderFingerprint -import app.revanced.patches.youtube.utils.fix.client.fingerprints.BackgroundPlaybackPlayerResponseFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildInitPlaybackRequestFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildPlaybackStatsRequestURIFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildPlayerRequestURIFingerprint @@ -27,6 +25,7 @@ import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlayerRe import app.revanced.patches.youtube.utils.fix.client.fingerprints.NerdsStatsVideoFormatBuilderFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.OrganicPlaybackContextModelFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.PlayerGestureConfigSyntheticFingerprint +import app.revanced.patches.youtube.utils.fix.client.fingerprints.PlayerResponseModelBackgroundAudioPlaybackFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.SetPlayerRequestClientTypeFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.UserAgentHeaderBuilderFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH @@ -59,7 +58,7 @@ object SpoofClientPatch : BaseBytecodePatch( name = "Spoof client", description = "Adds options to spoof the client to allow video playback.", dependencies = setOf( - // Required to fix background playback issue of live stream on iOS client. + // Required since iOS livestream fix partially enables background playback. BackgroundPlaybackPatch::class, PlayerTypeHookPatch::class, @@ -81,13 +80,6 @@ object SpoofClientPatch : BaseBytecodePatch( CreatePlayerRequestBodyWithVersionReleaseFingerprint, UserAgentHeaderBuilderFingerprint, - // Background playback in live stream. - BackgroundPlaybackPlayerResponseFingerprint, - - // Watch history. - BuildPlaybackStatsRequestURIFingerprint, - OrganicPlaybackContextModelFingerprint, - // Player gesture config. PlayerGestureConfigSyntheticFingerprint, @@ -95,6 +87,13 @@ object SpoofClientPatch : BaseBytecodePatch( CreatePlaybackSpeedMenuItemFingerprint, PlaybackRateBottomSheetBuilderFingerprint, + // Livestream audio only background playback. + PlayerResponseModelBackgroundAudioPlaybackFingerprint, + + // Watch history. + BuildPlaybackStatsRequestURIFingerprint, + OrganicPlaybackContextModelFingerprint, + // Nerds stats video format. NerdsStatsVideoFormatBuilderFingerprint, ) @@ -106,6 +105,10 @@ object SpoofClientPatch : BaseBytecodePatch( override fun execute(context: BytecodeContext) { + var settingArray = arrayOf( + "SETTINGS: SPOOF_CLIENT" + ) + // region Block /initplayback requests to fall back to /get_watch requests. BuildInitPlaybackRequestFingerprint.resultOrThrow().let { @@ -401,22 +404,13 @@ object SpoofClientPatch : BaseBytecodePatch( // endregion // region fix background playback in live stream, if spoofing to iOS - - /** - * If the return value of this method is true, background playback is always enabled. - * - * If [BackgroundPlaybackPatch] is excluded, there may be unintended behavior. - * Therefore, [BackgroundPlaybackPatch] must be included. - * - * Also, [PlayerTypeHookPatch] is required to disable background playback in Shorts. - */ - BackgroundPlaybackPlayerResponseFingerprint.resultOrThrow().mutableMethod.apply { + // This force enables audio background playback. + PlayerResponseModelBackgroundAudioPlaybackFingerprint.resultOrThrow().mutableMethod.apply { addInstructionsWithLabels( 0, """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceEnableBackgroundPlayback()Z + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideBackgroundAudioPlayback()Z move-result v0 if-eqz v0, :disabled - const/4 v0, 0x1 return v0 """, ExternalLabel("disabled", getInstruction(0)) ) @@ -426,32 +420,34 @@ object SpoofClientPatch : BaseBytecodePatch( // region watch history if spoofing to iOS - BuildPlaybackStatsRequestURIFingerprint.resultOrThrow().let { - val walkerMethod = context.toMethodWalker(it.method) - .nextMethod(it.scanResult.patternScanResult!!.startIndex, true) - .getMethod() as MutableMethod + if (!SettingsPatch.upward1839) { + BuildPlaybackStatsRequestURIFingerprint.resultOrThrow().let { + val walkerMethod = + it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex) - walkerMethod.addInstructions( - 0, """ - invoke-static {p0}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideTrackingUrl(Landroid/net/Uri;)Landroid/net/Uri; - move-result-object p0 - """ - ) - } - - OrganicPlaybackContextModelFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - val insertIndex = it.scanResult.patternScanResult!!.endIndex - val insertRegister = getInstruction(insertIndex).registerA - - addInstruction( - insertIndex, - "invoke-static { v$insertRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setCpn(Ljava/lang/String;)V" + walkerMethod.addInstructions( + 0, """ + invoke-static {p0}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideTrackingUrl(Landroid/net/Uri;)Landroid/net/Uri; + move-result-object p0 + """ ) } - } - TrackingUrlHookPatch.hookTrackingUrl("$INTEGRATIONS_CLASS_DESCRIPTOR->setTrackingUriParameter(Landroid/net/Uri;)V") + OrganicPlaybackContextModelFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val insertIndex = it.scanResult.patternScanResult!!.endIndex + val insertRegister = + getInstruction(insertIndex).registerA + + addInstruction( + insertIndex, + "invoke-static { v$insertRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setCpn(Ljava/lang/String;)V" + ) + } + } + + TrackingUrlHookPatch.hookTrackingUrl("$INTEGRATIONS_CLASS_DESCRIPTOR->setTrackingUriParameter(Landroid/net/Uri;)V") + } // endregion @@ -482,16 +478,18 @@ object SpoofClientPatch : BaseBytecodePatch( // endregion - context.updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "SpoofClient") + if (!SettingsPatch.upward1839) { + settingArray += "SETTINGS: IOS_CLIENT_SIDE_EFFECT_1838" + } else { + settingArray += "SETTINGS: IOS_CLIENT_SIDE_EFFECT_1839" + + context.updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "SpoofClient") + } /** * Add settings */ - SettingsPatch.addPreference( - arrayOf( - "SETTINGS: SPOOF_CLIENT" - ) - ) + SettingsPatch.addPreference(settingArray) SettingsPatch.updatePatchStatus(this) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/BackgroundPlaybackPlayerResponseFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt similarity index 93% rename from src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/BackgroundPlaybackPlayerResponseFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt index 5fe04c03d..30ec622e1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/BackgroundPlaybackPlayerResponseFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt @@ -11,7 +11,7 @@ import com.android.tools.smali.dexlib2.Opcode * This fingerprint seems to break easily because there are many [Opcode] patterns, but it is not. * This fingerprint has been tested on all versions from YouTube 17.34.36 to YouTube 19.29.42. */ -internal object BackgroundPlaybackPlayerResponseFingerprint : MethodFingerprint( +internal object PlayerResponseModelBackgroundAudioPlaybackFingerprint : MethodFingerprint( returnType = "Z", accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml index 4c8ec6aa9..b21ad1004 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -1613,12 +1613,16 @@ Limitation: Feed videos will play for less than 1 minute before encountering pla About iOS + "Spoof client to iOS. + +Side effects include: +• HDR video is supported only on AV1 codec. +• Watch time is not saved in watch history on brand account." "Spoof client to iOS. Side effects include: • HDR video is supported only on AV1 codec. -• Watch history does not work with a brand account. -• Live streams cannot play as audio-only." +• Watch history does not work with a brand account." Android Testsuite "Spoof client to Android Testsuite. diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 4319a60af..5a6a0229a 100644 --- a/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -619,8 +619,15 @@ - - + SETTINGS: SPOOF_CLIENT --> + + + + + +