diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/ProtobufParameterBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/PlayerParameterBuilderFingerprint.kt similarity index 93% rename from src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/ProtobufParameterBuilderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/PlayerParameterBuilderFingerprint.kt index bdcbfce42..8e78bdb18 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/ProtobufParameterBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/PlayerParameterBuilderFingerprint.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -object ProtobufParameterBuilderFingerprint : MethodFingerprint( +object PlayerParameterBuilderFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, returnType = "L", parameters = listOf( diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/PlayerResponseModelImplFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/PlayerResponseModelImplFingerprint.kt new file mode 100644 index 000000000..7f9bd3a90 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/PlayerResponseModelImplFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.utils.fix.parameter.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.util.bytecode.isWideLiteralExists +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +object PlayerResponseModelImplFingerprint : 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 = { methodDef, _ -> + methodDef.definingClass.endsWith("/PlayerResponseModelImpl;") && methodDef.isWideLiteralExists( + 55735497 + ) + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/ScrubbedPreviewLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/ScrubbedPreviewLayoutFingerprint.kt deleted file mode 100644 index b326ed664..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/ScrubbedPreviewLayoutFingerprint.kt +++ /dev/null @@ -1,28 +0,0 @@ -package app.revanced.patches.youtube.utils.fix.parameter.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch.Companion.Thumbnail -import app.revanced.util.bytecode.isWideLiteralExists -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object ScrubbedPreviewLayoutFingerprint : MethodFingerprint( - 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. - customFingerprint = { methodDef, _ -> methodDef.isWideLiteralExists(Thumbnail) } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/StoryboardRendererSpecFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/StoryboardRendererSpecFingerprint.kt new file mode 100644 index 000000000..22f944c31 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/fingerprints/StoryboardRendererSpecFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.utils.fix.parameter.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +object StoryboardRendererSpecFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + returnType = "L", + parameters = listOf("Ljava/lang/String;", "J"), + strings = listOf("\\|"), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/patch/SpoofPlayerParameterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/patch/SpoofPlayerParameterPatch.kt index 4d23cecc2..473544837 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/patch/SpoofPlayerParameterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/patch/SpoofPlayerParameterPatch.kt @@ -5,23 +5,26 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name 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.removeInstruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.youtube.utils.annotations.YouTubeCompatibility -import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.ProtobufParameterBuilderFingerprint -import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.ScrubbedPreviewLayoutFingerprint +import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.PlayerParameterBuilderFingerprint +import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.PlayerResponseModelImplFingerprint +import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardRendererSpecFingerprint import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardThumbnailFingerprint import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardThumbnailParentFingerprint import app.revanced.patches.youtube.utils.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch +import app.revanced.patches.youtube.utils.videoid.general.patch.VideoIdPatch import app.revanced.util.integrations.Constants.MISC_PATH import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @Patch @Name("Spoof player parameters") @@ -29,35 +32,42 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @DependsOn( [ SharedResourceIdPatch::class, - PlayerTypeHookPatch::class + PlayerTypeHookPatch::class, + VideoIdPatch::class ] ) @YouTubeCompatibility class SpoofPlayerParameterPatch : BytecodePatch( listOf( - ProtobufParameterBuilderFingerprint, - ScrubbedPreviewLayoutFingerprint, + PlayerParameterBuilderFingerprint, + PlayerResponseModelImplFingerprint, + StoryboardRendererSpecFingerprint, StoryboardThumbnailParentFingerprint ) ) { override fun execute(context: BytecodeContext) { - // hook parameter - ProtobufParameterBuilderFingerprint.result?.let { + /** + * Hook player parameter + */ + PlayerParameterBuilderFingerprint.result?.let { it.mutableMethod.apply { - val protobufParam = 3 + val videoIdRegister = 1 + val playerParameterRegister = 3 addInstructions( 0, """ - invoke-static {p$protobufParam}, $INTEGRATIONS_CLASS_DESCRIPTOR->overridePlayerParameter(Ljava/lang/String;)Ljava/lang/String; - move-result-object p$protobufParam + invoke-static {p$videoIdRegister, p$playerParameterRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + move-result-object p$playerParameterRegister """ ) } - } ?: throw ProtobufParameterBuilderFingerprint.exception + } ?: throw PlayerParameterBuilderFingerprint.exception - // When the player parameter is spoofed in incognito mode, this value will always be false - // If this value is true, the timestamp and chapter are shown when tapping the seekbar. + /** + * Forces the SeekBar thumbnail preview container to be shown + * I don't think this code is needed anymore + */ StoryboardThumbnailParentFingerprint.result?.classDef?.let { classDef -> StoryboardThumbnailFingerprint.also { it.resolve( @@ -84,23 +94,39 @@ class SpoofPlayerParameterPatch : BytecodePatch( } ?: throw StoryboardThumbnailFingerprint.exception } ?: throw StoryboardThumbnailParentFingerprint.exception - // Seekbar thumbnail now show up but are always a blank image. - // Additional changes are needed to force the client to generate the thumbnails (assuming it's possible), - // but for now hide the empty thumbnail. - ScrubbedPreviewLayoutFingerprint.result?.let { + /** + * Hook StoryBoard Renderer URL + * TODO: Find a way to increase the quality of SeekBar thumbnail previews + */ + PlayerResponseModelImplFingerprint.result?.let { it.mutableMethod.apply { - val endIndex = it.scanResult.patternScanResult!!.endIndex - val imageViewFieldName = getInstruction(endIndex).reference + val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex + val getStoryBoardRegister = + getInstruction(getStoryBoardIndex).registerA 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 + getStoryBoardIndex, """ + invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec()Ljava/lang/String; + move-result-object v$getStoryBoardRegister """ ) } - } ?: throw ScrubbedPreviewLayoutFingerprint.exception + } ?: throw PlayerResponseModelImplFingerprint.exception + + StoryboardRendererSpecFingerprint.result?.let { + it.mutableMethod.apply { + val storyBoardUrlParams = 0 + + addInstructionsWithLabels( + 0, """ + if-nez p$storyBoardUrlParams, :ignore + invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec()Ljava/lang/String; + move-result-object p$storyBoardUrlParams + """, ExternalLabel("ignore", getInstruction(0)) + ) + } + } ?: throw StoryboardRendererSpecFingerprint.exception + /** * Add settings diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt index 17184e5e9..7084f396c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt @@ -71,7 +71,6 @@ class SharedResourceIdPatch : ResourcePatch { var Scrubbing: Long = -1 var SettingsBooleanTimeRangeDialog: Long = -1 var SuggestedAction: Long = -1 - var Thumbnail: Long = -1 var ToolBarPaddingHome: Long = -1 var ToolTipContentView: Long = -1 var TotalTime: Long = -1 @@ -149,7 +148,6 @@ class SharedResourceIdPatch : ResourcePatch { Scrubbing = find(DIMEN, "vertical_touch_offset_to_enter_fine_scrubbing") SettingsBooleanTimeRangeDialog = find(LAYOUT, "setting_boolean_time_range_dialog") SuggestedAction = find(LAYOUT, "suggested_action") - Thumbnail = find(ID, "thumbnail") ToolBarPaddingHome = find(DIMEN, "toolbar_padding_home_action_up") ToolTipContentView = find(LAYOUT, "tooltip_content_view") TotalTime = find(STRING, "total_time") diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml index 5bf53f230..c2559e7b7 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -607,11 +607,9 @@ If later turned off, the old UI may remain until clear the app data" "Spoofs player parameters to prevent playback issues Known issues -• Ambient mode may not work -• Clip cannot be played normally -• Downloading videos may not work -• Filmstrip overlay are always hidden -• Seekbar thumbnails are hidden" +• Enhanced bitrate is not available +• Offline downloads may not work +• SeekBar thumbnail preview quality is very low" Spoof player parameter Swipe controls The amount of threshold for swipe to occur