From dfa94d70f65150d6ef24ea6378b8e6a317055186 Mon Sep 17 00:00:00 2001 From: Zain Date: Wed, 18 Sep 2024 05:45:02 +0700 Subject: [PATCH] fix(YouTube): Fix issues related to playback by replace streaming data (#3582) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Co-authored-by: oSumAtrIX --- api/revanced-patches.api | 6 + .../misc/fix/playback/SpoofClientPatch.kt | 396 +----------------- .../misc/fix/playback/SpoofSignaturePatch.kt | 235 +---------- .../playback/SpoofSignatureResourcePatch.kt | 12 +- .../fix/playback/SpoofVideoStreamsPatch.kt | 287 +++++++++++++ .../BuildMediaDataSourceFingerprint.kt | 22 + .../fingerprints/BuildRequestFingerprint.kt | 31 +- .../CreatePlaybackSpeedMenuItemFingerprint.kt | 34 -- .../CreatePlayerRequestBodyFingerprint.kt | 15 - ...tePlayerRequestBodyWithModelFingerprint.kt | 31 -- ...equestBodyWithVersionReleaseFingerprint.kt | 31 -- .../CreateStreamingDataFingerprint.kt | 24 ++ .../fingerprints/ParamsMapPutFingerprint.kt | 25 -- ...PlayerGestureConfigSyntheticFingerprint.kt | 49 --- ...ModelBackgroundAudioPlaybackFingerprint.kt | 25 -- ...ayerResponseModelImplGeneralFingerprint.kt | 24 -- ...rResponseModelImplLiveStreamFingerprint.kt | 24 -- ...nseModelImplRecommendedLevelFingerprint.kt | 24 -- ...ProtobufClassParseByteBufferFingerprint.kt | 19 + .../SetPlayerRequestClientTypeFingerprint.kt | 13 - ...rePatchScrubbedPreviewLayoutFingerprint.kt | 28 -- .../StatsQueryParameterFingerprint.kt | 8 - ...dererDecoderRecommendedLevelFingerprint.kt | 24 -- ...toryboardRendererDecoderSpecFingerprint.kt | 24 -- .../StoryboardRendererSpecFingerprint.kt | 13 - .../StoryboardThumbnailFingerprint.kt | 24 -- .../StoryboardThumbnailParentFingerprint.kt | 18 - .../youtube/misc/gms/GmsCoreSupportPatch.kt | 11 +- .../resources/addresources/values/arrays.xml | 24 +- .../resources/addresources/values/strings.xml | 52 +-- 30 files changed, 427 insertions(+), 1126 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildMediaDataSourceFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreateStreamingDataFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerGestureConfigSyntheticFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevelFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ProtobufClassParseByteBufferFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SetPlayerRequestClientTypeFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererSpecFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index c79665585..f94f26b01 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1916,6 +1916,12 @@ public final class app/revanced/patches/youtube/misc/fix/playback/SpoofSignature public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } +public final class app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch; public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object; diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt index f9ad8dd76..619d46c9c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt @@ -1,399 +1,11 @@ package app.revanced.patches.youtube.misc.fix.playback import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.getInstructions -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchException -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.all.misc.resources.AddResourcesPatch -import app.revanced.patches.shared.misc.settings.preference.ListPreference -import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackPatch -import app.revanced.patches.youtube.misc.fix.playback.fingerprints.* -import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch -import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow -import app.revanced.util.resultOrThrow -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -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.TypeReference -import com.android.tools.smali.dexlib2.immutable.ImmutableMethod -import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter -@Patch( - name = "Spoof client", - description = "Spoofs the client to allow video playback.", - dependencies = [ - SettingsPatch::class, - AddResourcesPatch::class, - UserAgentClientSpoofPatch::class, - // Required since iOS livestream fix partially enables background playback. - BackgroundPlaybackPatch::class, - PlayerTypeHookPatch::class, - ], - compatiblePackages = [ - CompatiblePackage( - "com.google.android.youtube", - [ - // This patch works with these versions, - // but the dependent background playback patch does not. - // "18.37.36", - // "18.38.44", - // "18.43.45", - // "18.44.41", - // "18.45.43", - "18.48.39", - "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.38", - "19.10.39", - "19.11.43", - "19.12.41", - "19.13.37", - "19.14.43", - "19.15.36", - "19.16.39", - ], - ), - ], -) +@Deprecated("This patch is obsolete.", replaceWith = ReplaceWith("SpoofVideoStreamsPatch")) object SpoofClientPatch : BytecodePatch( - setOf( - // Client type spoof. - BuildInitPlaybackRequestFingerprint, - BuildPlayerRequestURIFingerprint, - SetPlayerRequestClientTypeFingerprint, - CreatePlayerRequestBodyFingerprint, - CreatePlayerRequestBodyWithModelFingerprint, - CreatePlayerRequestBodyWithVersionReleaseFingerprint, - - // Player gesture config. - PlayerGestureConfigSyntheticFingerprint, - - // Player speed menu item. - CreatePlaybackSpeedMenuItemFingerprint, - - // Video qualities missing. - BuildRequestFingerprint, - - // Livestream audio only background playback. - PlayerResponseModelBackgroundAudioPlaybackFingerprint, - ) + dependencies = setOf(SpoofVideoStreamsPatch::class), ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/youtube/patches/spoof/SpoofClientPatch;" - private const val CLIENT_INFO_CLASS_DESCRIPTOR = - "Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;" - private const val REQUEST_CLASS_DESCRIPTOR = - "Lorg/chromium/net/ExperimentalUrlRequest;" - private const val REQUEST_BUILDER_CLASS_DESCRIPTOR = - "Lorg/chromium/net/ExperimentalUrlRequest\$Builder;" - - override fun execute(context: BytecodeContext) { - AddResourcesPatch(this::class) - - SettingsPatch.PreferenceScreen.MISC.addPreferences( - PreferenceScreen( - key = "revanced_spoof_client_screen", - sorting = PreferenceScreen.Sorting.UNSORTED, - preferences = setOf( - SwitchPreference("revanced_spoof_client"), - ListPreference("revanced_spoof_client_type", - summaryKey = null, - entriesKey = "revanced_spoof_client_type_entries", - entryValuesKey = "revanced_spoof_client_type_entry_values" - ), - SwitchPreference("revanced_spoof_client_ios_force_avc"), - NonInteractivePreference("revanced_spoof_client_about_android_ios"), - NonInteractivePreference("revanced_spoof_client_about_android_vr") - ) - ) - ) - - // region Block /initplayback requests to fall back to /get_watch requests. - - BuildInitPlaybackRequestFingerprint.resultOrThrow().let { - val moveUriStringIndex = it.scanResult.patternScanResult!!.startIndex - - it.mutableMethod.apply { - val targetRegister = getInstruction(moveUriStringIndex).registerA - - addInstructions( - moveUriStringIndex + 1, - """ - invoke-static { v$targetRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$targetRegister - """, - ) - } - } - - // endregion - - // region Block /get_watch requests to fall back to /player requests. - - BuildPlayerRequestURIFingerprint.resultOrThrow().let { - val invokeToStringIndex = it.scanResult.patternScanResult!!.startIndex - - it.mutableMethod.apply { - val uriRegister = getInstruction(invokeToStringIndex).registerC - - addInstructions( - invokeToStringIndex, - """ - invoke-static { v$uriRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri; - move-result-object v$uriRegister - """, - ) - } - } - - // endregion - - // region Get field references to be used below. - - val (clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField) = - SetPlayerRequestClientTypeFingerprint.resultOrThrow().let { result -> - // Field in the player request object that holds the client info object. - val clientInfoField = result.mutableMethod - .getInstructions().find { instruction -> - // requestMessage.clientInfo = clientInfoBuilder.build(); - instruction.opcode == Opcode.IPUT_OBJECT && - instruction.getReference()?.type == CLIENT_INFO_CLASS_DESCRIPTOR - }?.getReference() ?: throw PatchException("Could not find clientInfoField") - - // Client info object's client type field. - val clientInfoClientTypeField = result.mutableMethod - .getInstruction(result.scanResult.patternScanResult!!.endIndex) - .getReference() ?: throw PatchException("Could not find clientInfoClientTypeField") - - // Client info object's client version field. - val clientInfoClientVersionField = result.mutableMethod - .getInstruction(result.scanResult.stringsScanResult!!.matches.first().index + 1) - .getReference() - ?: throw PatchException("Could not find clientInfoClientVersionField") - - Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField) - } - - val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let { - val getClientModelIndex = - CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method) - - // The next IPUT_OBJECT instruction after getting the client model is setting the client model field. - val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) { - opcode == Opcode.IPUT_OBJECT - } - - it.mutableMethod.getInstruction(index).getReference() - ?: throw PatchException("Could not find clientInfoClientModelField") - } - - val clientInfoOsVersionField = CreatePlayerRequestBodyWithVersionReleaseFingerprint.resultOrThrow().let { - val getOsVersionIndex = - CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction(it.method) - - // The next IPUT_OBJECT instruction after getting the client os version is setting the client os version field. - val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getOsVersionIndex) { - opcode == Opcode.IPUT_OBJECT - } - - it.mutableMethod.getInstruction(index).getReference() - ?: throw PatchException("Could not find clientInfoOsVersionField") - } - - // endregion - - // region Spoof client type for /player requests. - - CreatePlayerRequestBodyFingerprint.resultOrThrow().let { result -> - val setClientInfoMethodName = "patch_setClientInfo" - val checkCastIndex = result.scanResult.patternScanResult!!.startIndex - var clientInfoContainerClassName: String - - result.mutableMethod.apply { - val checkCastInstruction = getInstruction(checkCastIndex) - val requestMessageInstanceRegister = checkCastInstruction.registerA - clientInfoContainerClassName = checkCastInstruction.getReference()!!.type - - addInstruction( - checkCastIndex + 1, - "invoke-static { v$requestMessageInstanceRegister }," + - " ${result.classDef.type}->$setClientInfoMethodName($clientInfoContainerClassName)V", - ) - } - - // Change client info to use the spoofed values. - // Do this in a helper method, to remove the need of picking out multiple free registers from the hooked code. - result.mutableClass.methods.add( - ImmutableMethod( - result.mutableClass.type, - setClientInfoMethodName, - listOf(ImmutableMethodParameter(clientInfoContainerClassName, null, "clientInfoContainer")), - "V", - AccessFlags.PRIVATE or AccessFlags.STATIC, - null, - null, - MutableMethodImplementation(3), - ).toMutable().apply { - addInstructions( - """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isClientSpoofingEnabled()Z - move-result v0 - if-eqz v0, :disabled - - iget-object v0, p0, $clientInfoField - - # Set client type to the spoofed value. - iget v1, v0, $clientInfoClientTypeField - invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientTypeId(I)I - move-result v1 - iput v1, v0, $clientInfoClientTypeField - - # Set client model to the spoofed value. - iget-object v1, v0, $clientInfoClientModelField - invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientModel(Ljava/lang/String;)Ljava/lang/String; - move-result-object v1 - iput-object v1, v0, $clientInfoClientModelField - - # Set client version to the spoofed value. - iget-object v1, v0, $clientInfoClientVersionField - invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String; - move-result-object v1 - iput-object v1, v0, $clientInfoClientVersionField - - # Set client os version to the spoofed value. - iget-object v1, v0, $clientInfoOsVersionField - invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getOsVersion(Ljava/lang/String;)Ljava/lang/String; - move-result-object v1 - iput-object v1, v0, $clientInfoOsVersionField - - :disabled - return-void - """, - ) - }, - ) - } - - // endregion - - // region Fix player gesture if spoofing to iOS. - - PlayerGestureConfigSyntheticFingerprint.resultOrThrow().let { - val endIndex = it.scanResult.patternScanResult!!.endIndex - val downAndOutLandscapeAllowedIndex = endIndex - 3 - val downAndOutPortraitAllowedIndex = endIndex - 9 - - arrayOf( - downAndOutLandscapeAllowedIndex, - downAndOutPortraitAllowedIndex, - ).forEach { index -> - val gestureAllowedMethod = context.toMethodWalker(it.mutableMethod) - .nextMethod(index, true) - .getMethod() as MutableMethod - - gestureAllowedMethod.apply { - val isAllowedIndex = getInstructions().lastIndex - val isAllowed = getInstruction(isAllowedIndex).registerA - - addInstructions( - isAllowedIndex, - """ - invoke-static { v$isAllowed }, $INTEGRATIONS_CLASS_DESCRIPTOR->enablePlayerGesture(Z)Z - move-result v$isAllowed - """, - ) - } - } - } - - // endregion - - // region Fix livestream audio only background play if spoofing to iOS. - // This force enables audio background playback. - - PlayerResponseModelBackgroundAudioPlaybackFingerprint.resultOrThrow().mutableMethod.addInstructions( - 0, - """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideBackgroundAudioPlayback()Z - move-result v0 - if-eqz v0, :do_not_override - return v0 - :do_not_override - nop - """ - ) - - // endregion - - // Fix playback speed menu item if spoofing to iOS. - - CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let { - val scanResult = it.scanResult.patternScanResult!! - if (scanResult.startIndex != 0) throw PatchException("Unexpected start index: ${scanResult.startIndex}") - - it.mutableMethod.apply { - // Find the conditional check if the playback speed menu item is not created. - val shouldCreateMenuIndex = - indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ } - val shouldCreateMenuRegister = getInstruction(shouldCreateMenuIndex).registerA - - addInstructions( - shouldCreateMenuIndex, - """ - invoke-static { v$shouldCreateMenuRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceCreatePlaybackSpeedMenu(Z)Z - move-result v$shouldCreateMenuRegister - """, - ) - } - } - - // endregion - - // region Fix video qualities missing, if spoofing to iOS by overriding the user agent. - - BuildRequestFingerprint.resultOrThrow().let { result -> - result.mutableMethod.apply { - val buildRequestIndex = getInstructions().lastIndex - 2 - val requestBuilderRegister = getInstruction(buildRequestIndex).registerC - - val newRequestBuilderIndex = result.scanResult.patternScanResult!!.endIndex - val urlRegister = getInstruction(newRequestBuilderIndex).registerD - - // Replace "requestBuilder.build(): Request" with "overrideUserAgent(requestBuilder, url): Request". - replaceInstruction( - buildRequestIndex, - "invoke-static { v$requestBuilderRegister, v$urlRegister }, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->" + - "overrideUserAgent(${REQUEST_BUILDER_CLASS_DESCRIPTOR}Ljava/lang/String;)" + - REQUEST_CLASS_DESCRIPTOR - ) - } - } - - // endregion - } -} + override fun execute(context: BytecodeContext) {} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt index c82597b3a..850d0d2c5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt @@ -1,239 +1,12 @@ package app.revanced.patches.youtube.misc.fix.playback import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.all.misc.resources.AddResourcesPatch -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import app.revanced.patches.youtube.misc.fix.playback.fingerprints.* -import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch -import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.patches.youtube.video.information.VideoInformationPatch -import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch -import app.revanced.util.exception -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -@Patch( - description = "Spoofs the signature to prevent playback issues.", - dependencies = [ - SettingsPatch::class, - PlayerTypeHookPatch::class, - PlayerResponseMethodHookPatch::class, - VideoInformationPatch::class, - SpoofSignatureResourcePatch::class, - AddResourcesPatch::class, - ], -) -@Deprecated("This patch will be removed in the future.") +@Deprecated("This patch is obsolete.", replaceWith = ReplaceWith("SpoofVideoStreamsPatch")) object SpoofSignaturePatch : BytecodePatch( - setOf( - PlayerResponseModelImplGeneralFingerprint, - PlayerResponseModelImplLiveStreamFingerprint, - PlayerResponseModelImplRecommendedLevelFingerprint, - StoryboardRendererSpecFingerprint, - StoryboardRendererDecoderSpecFingerprint, - StoryboardRendererDecoderRecommendedLevelFingerprint, - StoryboardThumbnailParentFingerprint, - SpoofSignaturePatchScrubbedPreviewLayoutFingerprint, - StatsQueryParameterFingerprint, - ParamsMapPutFingerprint, - ), + dependencies = setOf(SpoofVideoStreamsPatch::class), ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/youtube/patches/spoof/SpoofSignaturePatch;" - - override fun execute(context: BytecodeContext) { - AddResourcesPatch(this::class) - - SettingsPatch.PreferenceScreen.MISC.addPreferences( - PreferenceScreen( - key = "revanced_spoof_signature_verification_screen", - sorting = Sorting.UNSORTED, - preferences = setOf( - SwitchPreference("revanced_spoof_signature_verification_enabled"), - SwitchPreference("revanced_spoof_signature_in_feed_enabled"), - SwitchPreference("revanced_spoof_storyboard"), - ), - ), - ) - - // Hook the player parameters. - PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter( - "$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;", - ) - - // Force the seekbar time and chapters to always show up. - // This is used if the storyboard spec fetch fails, for viewing paid videos, - // or if storyboard spoofing is turned off. - StoryboardThumbnailParentFingerprint.result?.classDef?.let { classDef -> - StoryboardThumbnailFingerprint.also { - it.resolve( - context, - classDef, - ) - }.result?.let { - val endIndex = it.scanResult.patternScanResult!!.endIndex - // Replace existing instruction to preserve control flow label. - // The replaced return instruction always returns false - // (it is the 'no thumbnails found' control path), - // so there is no need to pass the existing return value to integrations. - it.mutableMethod.replaceInstruction( - endIndex, - """ - invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarThumbnailOverrideValue()Z - """, - ) - // Since this is end of the method must replace one line then add the rest. - it.mutableMethod.addInstructions( - endIndex + 1, - """ - move-result v0 - return v0 - """, - ) - } ?: throw StoryboardThumbnailFingerprint.exception - } - - // If storyboard spoofing is turned off, then hide the empty seekbar thumbnail view. - SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.result?.apply { - val endIndex = scanResult.patternScanResult!!.endIndex - mutableMethod.apply { - val imageViewFieldName = getInstruction(endIndex).reference - addInstructions( - implementation!!.instructions.lastIndex, - """ - iget-object v0, p0, $imageViewFieldName # copy imageview field to a register - invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->seekbarImageViewCreated(Landroid/widget/ImageView;)V - """, - ) - } - } ?: throw SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.exception - - /** - * Hook StoryBoard renderer url - */ - arrayOf( - PlayerResponseModelImplGeneralFingerprint, - PlayerResponseModelImplLiveStreamFingerprint, - ).forEach { fingerprint -> - fingerprint.result?.let { - it.mutableMethod.apply { - val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex - val getStoryBoardRegister = - getInstruction(getStoryBoardIndex).registerA - - addInstructions( - getStoryBoardIndex, - """ - invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$getStoryBoardRegister - """, - ) - } - } ?: throw fingerprint.exception - } - - // Hook recommended seekbar thumbnails quality level. - StoryboardRendererDecoderRecommendedLevelFingerprint.result?.let { - val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex - val originalValueRegister = it.mutableMethod - .getInstruction(moveOriginalRecommendedValueIndex).registerA - - it.mutableMethod.addInstructions( - moveOriginalRecommendedValueIndex + 1, - """ - invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I - move-result v$originalValueRegister - """, - ) - } ?: throw StoryboardRendererDecoderRecommendedLevelFingerprint.exception - - // Hook the recommended precise seeking thumbnails quality level. - PlayerResponseModelImplRecommendedLevelFingerprint.result?.let { - it.mutableMethod.apply { - val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex - val originalValueRegister = - getInstruction(moveOriginalRecommendedValueIndex).registerA - - addInstructions( - moveOriginalRecommendedValueIndex, - """ - invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I - move-result v$originalValueRegister - """, - ) - } - } ?: throw PlayerResponseModelImplRecommendedLevelFingerprint.exception - - StoryboardRendererSpecFingerprint.result?.let { - it.mutableMethod.apply { - val storyBoardUrlParams = 0 - - addInstructionsWithLabels( - 0, - """ - if-nez p$storyBoardUrlParams, :ignore - invoke-static { p$storyBoardUrlParams }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; - move-result-object p$storyBoardUrlParams - """, - ExternalLabel("ignore", getInstruction(0)), - ) - } - } ?: throw StoryboardRendererSpecFingerprint.exception - - // Hook the seekbar thumbnail decoder and use a NULL spec for live streams. - StoryboardRendererDecoderSpecFingerprint.result?.let { - val storyBoardUrlIndex = it.scanResult.patternScanResult!!.startIndex + 1 - val storyboardUrlRegister = - it.mutableMethod.getInstruction(storyBoardUrlIndex).registerA - - it.mutableMethod.addInstructions( - storyBoardUrlIndex + 1, - """ - invoke-static { v$storyboardUrlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardDecoderRendererSpec(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$storyboardUrlRegister - """, - ) - } ?: throw StoryboardRendererDecoderSpecFingerprint.exception - - // Fix stats not being tracked. - // Due to signature spoofing "adformat" is present in query parameters made for /stats requests, - // even though, for regular videos, it should not be. - // This breaks stats tracking. - // Replace the ad parameter with the video parameter in the query parameters. - StatsQueryParameterFingerprint.result?.let { - val putMethod = ParamsMapPutFingerprint.result?.method?.toString() - ?: throw ParamsMapPutFingerprint.exception - - it.mutableMethod.apply { - val adParamIndex = it.scanResult.stringsScanResult!!.matches.first().index - val videoParamIndex = adParamIndex + 3 - - // Replace the ad parameter with the video parameter. - replaceInstruction(adParamIndex, getInstruction(videoParamIndex)) - - // Call paramsMap.put instead of paramsMap.putIfNotExist - // because the key is already present in the map. - val putAdParamIndex = adParamIndex + 1 - val putIfKeyNotExistsInstruction = getInstruction(putAdParamIndex) - replaceInstruction( - putAdParamIndex, - "invoke-virtual { " + - "v${putIfKeyNotExistsInstruction.registerC}, " + - "v${putIfKeyNotExistsInstruction.registerD}, " + - "v${putIfKeyNotExistsInstruction.registerE} }, " + - putMethod, - ) - } - } ?: throw StatsQueryParameterFingerprint.exception - } + override fun execute(context: BytecodeContext) {} } + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt index c29c94381..ae164ebf1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt @@ -2,18 +2,8 @@ package app.revanced.patches.youtube.misc.fix.playback import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch -@Patch(dependencies = [ResourceMappingPatch::class]) @Deprecated("This patch will be removed in the future.") object SpoofSignatureResourcePatch : ResourcePatch() { - internal var scrubbedPreviewThumbnailResourceId: Long = -1 - - override fun execute(context: ResourceContext) { - scrubbedPreviewThumbnailResourceId = ResourceMappingPatch[ - "id", - "thumbnail", - ] - } + override fun execute(context: ResourceContext) {} } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt new file mode 100644 index 000000000..828b54784 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch.kt @@ -0,0 +1,287 @@ +package app.revanced.patches.youtube.misc.fix.playback + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +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.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference +import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildInitPlaybackRequestFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildMediaDataSourceFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildPlayerRequestURIFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildRequestFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreateStreamingDataFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.ProtobufClassParseByteBufferFingerprint +import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.immutable.ImmutableMethod +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter + +@Patch( + name = "Spoof video streams", + description = "Spoofs the client video streams to allow video playback.", + dependencies = [ + SettingsPatch::class, + AddResourcesPatch::class, + UserAgentClientSpoofPatch::class, + ], + compatiblePackages = [ + CompatiblePackage( + "com.google.android.youtube", + [ + "18.37.36", + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.36", + "19.04.38", + "19.05.36", + "19.06.39", + "19.07.40", + "19.08.36", + "19.09.38", + "19.10.39", + "19.11.43", + "19.12.41", + "19.13.37", + "19.14.43", + "19.15.36", + "19.16.39", + ], + ), + ], +) +object SpoofVideoStreamsPatch : BytecodePatch( + setOf( + BuildInitPlaybackRequestFingerprint, + BuildPlayerRequestURIFingerprint, + CreateStreamingDataFingerprint, + BuildMediaDataSourceFingerprint, + BuildRequestFingerprint, + ProtobufClassParseByteBufferFingerprint, + ), +) { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/youtube/patches/spoof/SpoofVideoStreamsPatch;" + + override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences( + PreferenceScreen( + key = "revanced_spoof_video_streams_screen", + sorting = PreferenceScreen.Sorting.UNSORTED, + preferences = setOf( + SwitchPreference("revanced_spoof_video_streams"), + ListPreference( + "revanced_spoof_video_streams_client_type", + summaryKey = null, + entriesKey = "revanced_spoof_video_streams_client_type_entries", + entryValuesKey = "revanced_spoof_video_streams_client_type_entry_values", + ), + SwitchPreference( + "revanced_spoof_video_streams_ios_force_avc", + tag = "app.revanced.integrations.youtube.settings.preference.ForceAVCSpoofingPreference", + ), + NonInteractivePreference("revanced_spoof_video_streams_about_ios"), + NonInteractivePreference("revanced_spoof_video_streams_about_android_vr"), + ), + ), + ) + + // region Block /initplayback requests to fall back to /get_watch requests. + + BuildInitPlaybackRequestFingerprint.resultOrThrow().let { + val moveUriStringIndex = it.scanResult.patternScanResult!!.startIndex + + it.mutableMethod.apply { + val targetRegister = getInstruction(moveUriStringIndex).registerA + + addInstructions( + moveUriStringIndex + 1, + """ + invoke-static { v$targetRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """, + ) + } + } + + // endregion + + // region Block /get_watch requests to fall back to /player requests. + + BuildPlayerRequestURIFingerprint.resultOrThrow().let { + val invokeToStringIndex = it.scanResult.patternScanResult!!.startIndex + + it.mutableMethod.apply { + val uriRegister = getInstruction(invokeToStringIndex).registerC + + addInstructions( + invokeToStringIndex, + """ + invoke-static { v$uriRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri; + move-result-object v$uriRegister + """, + ) + } + } + + // endregion + + // region Get replacement streams at player requests. + + BuildRequestFingerprint.resultOrThrow().mutableMethod.apply { + val newRequestBuilderIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "newUrlRequestBuilder" + } + val urlRegister = getInstruction(newRequestBuilderIndex).registerD + val freeRegister = getInstruction(newRequestBuilderIndex + 1).registerA + + addInstructions( + newRequestBuilderIndex, + """ + move-object v$freeRegister, p1 + invoke-static { v$urlRegister, v$freeRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V + """, + ) + } + + // endregion + + // region Replace the streaming data with the replacement streams. + + CreateStreamingDataFingerprint.resultOrThrow().let { result -> + result.mutableMethod.apply { + val setStreamDataMethodName = "patch_setStreamingData" + val resultMethodType = result.mutableClass.type + val videoDetailsIndex = result.scanResult.patternScanResult!!.endIndex + val videoDetailsRegister = getInstruction(videoDetailsIndex).registerA + val videoDetailsClass = getInstruction(videoDetailsIndex).getReference()!!.type + + addInstruction( + videoDetailsIndex + 1, + "invoke-direct { p0, v$videoDetailsRegister }, " + + "$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V", + ) + + val protobufClass = ProtobufClassParseByteBufferFingerprint.resultOrThrow().mutableMethod.definingClass + val setStreamingDataIndex = result.scanResult.patternScanResult!!.startIndex + + val playerProtoClass = getInstruction(setStreamingDataIndex + 1) + .getReference()!!.definingClass + + val setStreamingDataField = getInstruction(setStreamingDataIndex).getReference() + + val getStreamingDataField = getInstruction( + indexOfFirstInstructionOrThrow { + opcode == Opcode.IGET_OBJECT && getReference()?.definingClass == playerProtoClass + } + ).getReference() + + // Use a helper method to avoid the need of picking out multiple free registers from the hooked code. + result.mutableClass.methods.add( + ImmutableMethod( + resultMethodType, + setStreamDataMethodName, + listOf(ImmutableMethodParameter(videoDetailsClass, null, "videoDetails")), + "V", + AccessFlags.PRIVATE or AccessFlags.FINAL, + null, + null, + MutableMethodImplementation(9), + ).toMutable().apply { + addInstructionsWithLabels( + 0, + """ + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isSpoofingEnabled()Z + move-result v0 + if-eqz v0, :disabled + + # Get video id. + iget-object v2, p1, $videoDetailsClass->c:Ljava/lang/String; + if-eqz v2, :disabled + + # Get streaming data. + invoke-static { v2 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)Ljava/nio/ByteBuffer; + move-result-object v3 + if-eqz v3, :disabled + + # Parse streaming data. + sget-object v4, $playerProtoClass->a:$playerProtoClass + invoke-static { v4, v3 }, $protobufClass->parseFrom(${protobufClass}Ljava/nio/ByteBuffer;)$protobufClass + move-result-object v5 + check-cast v5, $playerProtoClass + + # Set streaming data. + iget-object v6, v5, $getStreamingDataField + if-eqz v6, :disabled + iput-object v6, p0, $setStreamingDataField + + :disabled + return-void + """, + ) + }, + ) + } + } + + // endregion + + // region Remove /videoplayback request body to fix playback. + // This is needed when using iOS client as streaming data source. + + BuildMediaDataSourceFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val targetIndex = getInstructions().lastIndex + + // Instructions are added just before the method returns, + // so there's no concern of clobbering in-use registers. + addInstructions( + targetIndex, + """ + # Field a: Stream uri. + # Field c: Http method. + # Field d: Post data. + move-object v0, p0 # method has over 15 registers and must copy p0 to a lower register. + iget-object v1, v0, $definingClass->a:Landroid/net/Uri; + iget v2, v0, $definingClass->c:I + iget-object v3, v0, $definingClass->d:[B + invoke-static { v1, v2, v3 }, $INTEGRATIONS_CLASS_DESCRIPTOR->removeVideoPlaybackPostBody(Landroid/net/Uri;I[B)[B + move-result-object v1 + iput-object v1, v0, $definingClass->d:[B + """, + ) + } + } + + // endregion + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildMediaDataSourceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildMediaDataSourceFingerprint.kt new file mode 100644 index 000000000..ad00203cc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildMediaDataSourceFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object BuildMediaDataSourceFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + returnType = "V", + parameters = listOf( + "Landroid/net/Uri;", + "J", + "I", + "[B", + "Ljava/util/Map;", + "J", + "J", + "Ljava/lang/String;", + "I", + "Ljava/lang/Object;" + ) +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildRequestFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildRequestFingerprint.kt index 49c4a76ee..8156547e1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildRequestFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildRequestFingerprint.kt @@ -3,13 +3,34 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode internal object BuildRequestFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, returnType = "Lorg/chromium/net/UrlRequest;", - opcodes = listOf( - Opcode.INVOKE_DIRECT, - Opcode.INVOKE_VIRTUAL - ) + customFingerprint = { methodDef, _ -> + // Different targets have slightly different parameters + + // Earlier targets have parameters: + //L + //Ljava/util/Map; + //[B + //L + //L + //L + //Lorg/chromium/net/UrlRequest$Callback; + + // Later targets have parameters: + //L + //Ljava/util/Map; + //[B + //L + //L + //L + //Lorg/chromium/net/UrlRequest\$Callback; + //L + + val parameterTypes = methodDef.parameterTypes + (parameterTypes.size == 7 || parameterTypes.size == 8) + && parameterTypes[1] == "Ljava/util/Map;" // URL headers. + } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt deleted file mode 100644 index 035771ce2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlaybackSpeedMenuItemFingerprint.kt +++ /dev/null @@ -1,34 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -internal object CreatePlaybackSpeedMenuItemFingerprint : MethodFingerprint( - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "V", - opcodes = listOf( - Opcode.IGET_OBJECT, // First instruction of the method - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.CONST_4, - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - null // MOVE_RESULT or MOVE_RESULT_OBJECT, Return value controls the creation of the playback speed menu item. - ), - // 19.01 and earlier is missing the second parameter. - // Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures. - customFingerprint = custom@{ methodDef, _ -> - // 19.01 and earlier parameters are: "[L" - // 19.02+ parameters are "[L", "F" - val parameterTypes = methodDef.parameterTypes - val firstParameter = parameterTypes.firstOrNull() - - if (firstParameter == null || !firstParameter.startsWith("[L")) { - return@custom false - } - - parameterTypes.size == 1 || (parameterTypes.size == 2 && parameterTypes[1] == "F") - } -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyFingerprint.kt deleted file mode 100644 index 5abe29e67..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.Opcode - -internal object CreatePlayerRequestBodyFingerprint : MethodFingerprint( - returnType = "V", - parameters = listOf("L"), - opcodes = listOf( - Opcode.CHECK_CAST, - Opcode.IGET, - Opcode.AND_INT_LIT16, - ), - strings = listOf("ms"), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt deleted file mode 100644 index eb9133005..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction -import app.revanced.util.containsWideLiteralInstructionValue -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.iface.Method -import com.android.tools.smali.dexlib2.iface.reference.FieldReference - -internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint( - returnType = "L", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf(), - customFingerprint = { methodDef, _ -> - methodDef.containsWideLiteralInstructionValue(1073741824) && - indexOfBuildModelInstruction(methodDef) >= 0 - }, -) { - fun indexOfBuildModelInstruction(methodDef: Method) = - methodDef.indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Landroid/os/Build;" && - reference.name == "MODEL" && - reference.type == "Ljava/lang/String;" - } -} - - diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt deleted file mode 100644 index 1fba488be..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction -import app.revanced.util.containsWideLiteralInstructionValue -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.iface.Method -import com.android.tools.smali.dexlib2.iface.reference.FieldReference - -internal object CreatePlayerRequestBodyWithVersionReleaseFingerprint : MethodFingerprint( - returnType = "L", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf(), - customFingerprint = { methodDef, _ -> - methodDef.containsWideLiteralInstructionValue(1073741824) && - indexOfBuildVersionReleaseInstruction(methodDef) >= 0 - }, -) { - fun indexOfBuildVersionReleaseInstruction(methodDef: Method) = - methodDef.indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Landroid/os/Build\$VERSION;" && - reference.name == "RELEASE" && - reference.type == "Ljava/lang/String;" - } -} - - diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreateStreamingDataFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreateStreamingDataFingerprint.kt new file mode 100644 index 000000000..c9b2221c9 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreateStreamingDataFingerprint.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object CreateStreamingDataFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + returnType = "V", + parameters = listOf("L"), + opcodes = listOf( + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IPUT_OBJECT + ), + customFingerprint = { methodDef, classDef -> + classDef.fields.any { field -> + field.name == "a" && field.type.endsWith("/StreamingDataOuterClass\$StreamingData;") + } + }, +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt deleted file mode 100644 index bb93acc88..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object ParamsMapPutFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf( - "Ljava/lang/String;", - "Ljava/lang/String;", - ), - opcodes = listOf( - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.MOVE_OBJECT, - Opcode.MOVE_OBJECT, - Opcode.MOVE_OBJECT, - Opcode.INVOKE_DIRECT_RANGE, - ), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerGestureConfigSyntheticFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerGestureConfigSyntheticFingerprint.kt deleted file mode 100644 index d691d7cfc..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerGestureConfigSyntheticFingerprint.kt +++ /dev/null @@ -1,49 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -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.MethodReference - -internal object PlayerGestureConfigSyntheticFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Ljava/lang/Object;"), - opcodes = listOf( - Opcode.SGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutLandscapeAllowed. - Opcode.MOVE_RESULT, - Opcode.CHECK_CAST, - Opcode.IPUT_BOOLEAN, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutPortraitAllowed. - Opcode.MOVE_RESULT, - Opcode.IPUT_BOOLEAN, - Opcode.RETURN_VOID, - ), - customFingerprint = { methodDef, classDef -> - fun indexOfDownAndOutAllowedInstruction(methodDef: Method) = - methodDef.indexOfFirstInstruction { - val reference = getReference() - reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" && - reference.parameterTypes.isEmpty() && - reference.returnType == "Z" - } - - // This method is always called "a" because this kind of class always has a single method. - methodDef.name == "a" && classDef.methods.count() == 2 && - indexOfDownAndOutAllowedInstruction(methodDef) >= 0 - }, -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt deleted file mode 100644 index afe153219..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelBackgroundAudioPlaybackFingerprint.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -internal object PlayerResponseModelBackgroundAudioPlaybackFingerprint : MethodFingerprint( - returnType = "Z", - accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, - parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), - opcodes = listOf( - Opcode.CONST_4, - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.GOTO, - Opcode.RETURN, - null, // Opcode.CONST_4 or Opcode.MOVE - Opcode.RETURN, - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt deleted file mode 100644 index 9328dd45c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.util.containsWideLiteralInstructionValue -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint( - returnType = "Ljava/lang/String;", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = emptyList(), - opcodes = listOf( - Opcode.RETURN_OBJECT, - Opcode.CONST_4, - Opcode.RETURN_OBJECT, - ), - customFingerprint = handler@{ methodDef, _ -> - if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false - - methodDef.containsWideLiteralInstructionValue(55735497) - }, -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt deleted file mode 100644 index 480bdb11f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.util.containsWideLiteralInstructionValue -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object PlayerResponseModelImplLiveStreamFingerprint : MethodFingerprint( - returnType = "Ljava/lang/String;", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = emptyList(), - opcodes = listOf( - Opcode.RETURN_OBJECT, - Opcode.CONST_4, - Opcode.RETURN_OBJECT, - ), - customFingerprint = handler@{ methodDef, _ -> - if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false - - methodDef.containsWideLiteralInstructionValue(70276274) - }, -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevelFingerprint.kt deleted file mode 100644 index 11de5b7fe..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevelFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import app.revanced.util.containsWideLiteralInstructionValue -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object PlayerResponseModelImplRecommendedLevelFingerprint : MethodFingerprint( - returnType = "I", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = emptyList(), - opcodes = listOf( - Opcode.SGET_OBJECT, - Opcode.IGET, - Opcode.RETURN, - ), - customFingerprint = handler@{ methodDef, _ -> - if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false - - methodDef.containsWideLiteralInstructionValue(55735497) - }, -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ProtobufClassParseByteBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ProtobufClassParseByteBufferFingerprint.kt new file mode 100644 index 000000000..b5fb83749 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ProtobufClassParseByteBufferFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object ProtobufClassParseByteBufferFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PROTECTED or AccessFlags.STATIC, + parameters = listOf("L", "Ljava/nio/ByteBuffer;"), + returnType = "L", + opcodes = listOf( + Opcode.SGET_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT, + ), + customFingerprint = { methodDef, _ -> methodDef.name == "parseFrom" }, +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SetPlayerRequestClientTypeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SetPlayerRequestClientTypeFingerprint.kt deleted file mode 100644 index 78c240ef4..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SetPlayerRequestClientTypeFingerprint.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.util.patch.LiteralValueFingerprint -import com.android.tools.smali.dexlib2.Opcode - -internal object SetPlayerRequestClientTypeFingerprint : LiteralValueFingerprint( - opcodes = listOf( - Opcode.IGET, - Opcode.IPUT, // Sets ClientInfo.clientId. - ), - strings = listOf("10.29"), - literalSupplier = { 134217728 } -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt deleted file mode 100644 index c15d94db9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt +++ /dev/null @@ -1,28 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patches.youtube.misc.fix.playback.SpoofSignatureResourcePatch -import app.revanced.util.patch.LiteralValueFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object SpoofSignaturePatchScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint( - accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, - returnType = "V", - parameters = listOf("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I", "I"), - opcodes = listOf( - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.IPUT_OBJECT, // preview imageview - ), - // This resource is used in ~ 40 different locations, but this method has a distinct list of parameters to match to. - literalSupplier = { SpoofSignatureResourcePatch.scrubbedPreviewThumbnailResourceId }, -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt deleted file mode 100644 index 24c812136..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object StatsQueryParameterFingerprint : MethodFingerprint( - strings = listOf("adunit"), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt deleted file mode 100644 index 482ca51a1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -/** - * Resolves to the same method as [StoryboardRendererDecoderSpecFingerprint]. - */ -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), - opcodes = listOf( - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT, - ), - strings = listOf("#-1#"), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt deleted file mode 100644 index a2a31800f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -/** - * Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint]. - */ -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), - opcodes = listOf( - Opcode.INVOKE_INTERFACE, // First instruction of the method. - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.IF_NEZ, - ), - strings = listOf("#-1#"), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererSpecFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererSpecFingerprint.kt deleted file mode 100644 index cc00d0ccd..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererSpecFingerprint.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object StoryboardRendererSpecFingerprint : MethodFingerprint( - accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, - returnType = "L", - parameters = listOf("Ljava/lang/String;", "J"), - strings = listOf("\\|"), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailFingerprint.kt deleted file mode 100644 index 88e368db5..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -/** - * Resolves using the class found in [StoryboardThumbnailParentFingerprint]. - */ -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object StoryboardThumbnailFingerprint : MethodFingerprint( - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "Z", - parameters = listOf(), - opcodes = listOf( - Opcode.MOVE_RESULT, - Opcode.IF_GTZ, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.RETURN, - Opcode.RETURN, // Last instruction of method. - ), -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt deleted file mode 100644 index f8e449405..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -/** - * Here lies code that creates the seekbar thumbnails. - * - * An additional change here might force the thumbnails to be created, - * or possibly a change somewhere else (maybe involving YouTube 18.23.35 class `hte`) - */ -@Deprecated("Fingerprint is obsolete and will be deleted soon") -internal object StoryboardThumbnailParentFingerprint : MethodFingerprint( - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "Landroid/graphics/Bitmap;", - strings = listOf("Storyboard regionDecoder.decodeRegion exception - "), -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt index 67a47c71d..e74a3d11e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt @@ -32,12 +32,11 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch( CompatiblePackage( "com.google.android.youtube", setOf( - // Patch supports these versions but ClientSpoof does not. - // "18.37.36", - // "18.38.44", - // "18.43.45", - // "18.44.41", - // "18.45.43", + "18.37.36", + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.43", "18.48.39", "18.49.37", "19.01.34", diff --git a/src/main/resources/addresources/values/arrays.xml b/src/main/resources/addresources/values/arrays.xml index f1700555f..cee01a7a3 100644 --- a/src/main/resources/addresources/values/arrays.xml +++ b/src/main/resources/addresources/values/arrays.xml @@ -1,5 +1,17 @@ + + + + iOS + Android VR + + + + IOS + ANDROID_VR + + @string/revanced_spoof_app_version_target_entry_1 @@ -97,18 +109,6 @@ END - - - - iOS - Android VR - - - - IOS - ANDROID_VR - - @string/revanced_video_quality_default_entry_1 diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 6c1cef7a7..d34a38e3b 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -1148,41 +1148,23 @@ This is because Crowdin requires temporarily flattening this file and removing t Slide to seek is enabled Slide to seek is not enabled - - Spoof client - Spoof the client to prevent playback issues - Spoof client - Client is spoofed - Client is not spoofed\n\nVideo playback may not work - Turning off this setting may cause video playback issues. - Spoof client type - Force iOS AVC (H.264) - iOS video codec is AVC - iOS video codec is AVC, VP9, or AV1 - Enabling this might improve battery life and fix playback stuttering.\n\nAVC has a maximum resolution of 1080p, and video playback will use more internet data than VP9 or AV1. - iOS spoofing side effects - • HDR is supported only with AV1 codec\n• Watch history does not work with a brand account - Android VR spoofing side effects - • No HDR video\n• Kids videos do not playback\n• Paused videos can randomly resume\n• Low quality Shorts seekbar thumbnails\n• Download action button is hidden\n• End screen cards are hidden - Spoof client thumbnails not available (API timed out) - Spoof client thumbnails temporarily not available: %s - - - - Spoof app signature - Spoof the app signature to prevent playback issues - Spoof app signature - App signature spoofed\n\nSide effects include:\n• Enhanced bitrate is not available\n• Videos cannot be downloaded\n• No seekbar thumbnails for paid videos - App signature not spoofed\n\nVideo playback may not work - Turning off this setting will cause video playback issues. - Spoof app signature in feed - App signature spoofed\n\nSide effects include:\n• Feed videos are missing subtitles\n• Automatically played feed videos will show up in your watch history - App signature not spoofed for feed videos\n\nFeed videos will play for less than 1 minute before encountering playback issues - Spoof storyboard - Storyboard spoofed - Storyboard not spoofed\n\nSide effects include:\n• No ambient mode\n• Seekbar thumbnails are hidden - Spoof storyboard temporarily not available (API timed out) - Spoof storyboard temporarily not available: %s + + Spoof video streams + Spoof the client video streams to prevent playback issues + Spoof video streams + Video streams are spoofed + Video streams are not spoofed\n\nVideo playback may not work + Turning off this setting may cause video playback issues. + Default client + Force AVC (H.264) + Video codec is AVC (H.264) + Video codec is VP9 or AV1 + Your device does not have VP9 hardware decoding, and this setting is always on when Client spoofing is enabled + Enabling this might improve battery life and fix playback stuttering.\n\nAVC has a maximum resolution of 1080p, and video playback will use more internet data than VP9 or AV1. + iOS spoofing side effects + • Movies or paid videos may not play\n• Livestreams start from the beginning + Android VR spoofing side effects + • Audio track menu is missing