diff --git a/CHANGELOG.md b/CHANGELOG.md index 868f9da507..9a5fa023d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,177 @@ +# [4.8.0-dev.24](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.23...v4.8.0-dev.24) (2024-05-21) + + +### Bug Fixes + +* **YouTube - Client spoof:** Spoof client to fix playback ([#3199](https://github.com/ReVanced/revanced-patches/issues/3199)) ([bec1eef](https://github.com/ReVanced/revanced-patches/commit/bec1eef10f2eb4e15696acb271357f1621543de1)) + +# [4.8.0-dev.23](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.22...v4.8.0-dev.23) (2024-05-18) + + +### Features + +* **Piccoma:** Add `Spoof Android device ID` patch ([#3145](https://github.com/ReVanced/revanced-patches/issues/3145)) ([d953c6b](https://github.com/ReVanced/revanced-patches/commit/d953c6bdd4315d2ba44845fd569a3d12ac4d1af0)) + +# [4.8.0-dev.22](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.21...v4.8.0-dev.22) (2024-05-18) + + +### Bug Fixes + +* Use correct preference key ([3732b2c](https://github.com/ReVanced/revanced-patches/commit/3732b2ce6b617b4c1c6647397b614f8a040eece3)) + +# [4.8.0-dev.21](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.20...v4.8.0-dev.21) (2024-05-18) + + +### Features + +* **Piccoma:** Add `Disable tracking` patch ([#3143](https://github.com/ReVanced/revanced-patches/issues/3143)) ([8ab9e8f](https://github.com/ReVanced/revanced-patches/commit/8ab9e8f89d2bd014138e31dab7004f8ba77cae10)) +* **YouTube - Navigation buttons:** Add option to hide navigation button labels ([#3189](https://github.com/ReVanced/revanced-patches/issues/3189)) ([f9dc705](https://github.com/ReVanced/revanced-patches/commit/f9dc7050513b9fdb7766838a63a172f1478296f7)) + +# [4.8.0-dev.20](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.19...v4.8.0-dev.20) (2024-05-16) + + +### Features + +* **YT Music:** Add support for `7.01.52` ([#3177](https://github.com/ReVanced/revanced-patches/issues/3177)) ([e9bfb25](https://github.com/ReVanced/revanced-patches/commit/e9bfb25dfe85754fd7fa5c9db934bb4fc52e4694)) + +# [4.8.0-dev.19](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.18...v4.8.0-dev.19) (2024-05-16) + + +### Features + +* **YouTube - Hide Shorts components:** Hide 'Buy super thanks' button ([#3176](https://github.com/ReVanced/revanced-patches/issues/3176)) ([89c1548](https://github.com/ReVanced/revanced-patches/commit/89c154861c8b3afa665542e97ff201c3e84410b2)) + +# [4.8.0-dev.18](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.17...v4.8.0-dev.18) (2024-05-14) + + +### Bug Fixes + +* **YouTube Music:** Make `Hide 'Get Music Premium' label` and `Remove upgrade button` compatible with latest version ([#3164](https://github.com/ReVanced/revanced-patches/issues/3164)) ([3ff20de](https://github.com/ReVanced/revanced-patches/commit/3ff20dee4aea49ca77dcd3fbe148287b55a2b5e3)) + +# [4.8.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.16...v4.8.0-dev.17) (2024-05-12) + + +### Features + +* **Photomath:** Support version `8.37.0` ([#3109](https://github.com/ReVanced/revanced-patches/issues/3109)) ([fb02b48](https://github.com/ReVanced/revanced-patches/commit/fb02b481e2be8c2bc4441dc5b3dc6a9df3a2a379)) + +# [4.8.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.15...v4.8.0-dev.16) (2024-05-12) + + +### Features + +* **WarnWetter - Promo code unlock:** Constrain to last working version ([#3110](https://github.com/ReVanced/revanced-patches/issues/3110)) ([92fc8aa](https://github.com/ReVanced/revanced-patches/commit/92fc8aaad80f8fad35b75e6de032692986211536)) + +# [4.8.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.14...v4.8.0-dev.15) (2024-05-11) + + +### Bug Fixes + +* **YouTube - Restore old video quality menu:** Show advanced quality menu in Shorts quality flyout ([#3155](https://github.com/ReVanced/revanced-patches/issues/3155)) ([c2b5bb7](https://github.com/ReVanced/revanced-patches/commit/c2b5bb723416e43a920817f97b9e0ee4ceab4f6b)) + +# [4.8.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.13...v4.8.0-dev.14) (2024-05-08) + + +### Bug Fixes + +* **YouTube - SponsorBlock:** Show correct segment times if video is over 24 hours in length ([#3138](https://github.com/ReVanced/revanced-patches/issues/3138)) ([6cdf697](https://github.com/ReVanced/revanced-patches/commit/6cdf697e8e47f6d53964497703dbe79fab3b1821)) + +# [4.8.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.12...v4.8.0-dev.13) (2024-05-06) + + +### Bug Fixes + +* **YouTube - Navigation buttons:** Adjust summary text of switch notification button ([#3130](https://github.com/ReVanced/revanced-patches/issues/3130)) ([cc8b4c9](https://github.com/ReVanced/revanced-patches/commit/cc8b4c913ed25d07fd4000cfd6318bb06a9d27c0)) + +# [4.8.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.11...v4.8.0-dev.12) (2024-05-06) + + +### Bug Fixes + +* **YouTube - Player flyout menu:** Remove obsolete `Hide report menu` ([d627d44](https://github.com/ReVanced/revanced-patches/commit/d627d44ad07fa32bb2f247ce24a3591ec5e1be0e)) + +# [4.8.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.10...v4.8.0-dev.11) (2024-05-06) + + +### Bug Fixes + +* **Reddit is Fun - Spoof client:** Fix login by updating the authorization subdomain from "old" to "ssl" ([b156cb1](https://github.com/ReVanced/revanced-patches/commit/b156cb1d8996c4314d59e3441c6b85d8f704cdff)) + +# [4.8.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.9...v4.8.0-dev.10) (2024-05-02) + + +### Features + +* **Tumblr:** Add `Disable Ad-Free Banner` patch ([#3091](https://github.com/ReVanced/revanced-patches/issues/3091)) ([54baf08](https://github.com/ReVanced/revanced-patches/commit/54baf08f777b7c975fa0b6508f0a4de19ac491f4)) + +# [4.8.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.8...v4.8.0-dev.9) (2024-04-29) + + +### Bug Fixes + +* Correctly handle patches jar path if it contains exclamation marks ([056e2d7](https://github.com/ReVanced/revanced-patches/commit/056e2d7dd5bbacb7dc6b109b3e2d44d55e7eb7d3)) + +# [4.8.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.7...v4.8.0-dev.8) (2024-04-23) + + +### Bug Fixes + +* **YouTube - Hide ads:** Fix string typo ([ecc56d6](https://github.com/ReVanced/revanced-patches/commit/ecc56d643a0c4e5f25b933431f097a03d4bf2e69)) + +# [4.8.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.6...v4.8.0-dev.7) (2024-04-23) + + +### Bug Fixes + +* URL decode path to JAR containing spaces to get JAR manifest ([#3079](https://github.com/ReVanced/revanced-patches/issues/3079)) ([e1bbcb3](https://github.com/ReVanced/revanced-patches/commit/e1bbcb338dd7fce895b606440bd6f040d5486a64)) + +# [4.8.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.5...v4.8.0-dev.6) (2024-04-23) + + +### Features + +* **YouTube - Hide ads:** Add option to hide the 'Visit store' button on channel pages ([#3077](https://github.com/ReVanced/revanced-patches/issues/3077)) ([03d2cfa](https://github.com/ReVanced/revanced-patches/commit/03d2cfafbf977340456598a848858ac9452c853f)) + +# [4.8.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.4...v4.8.0-dev.5) (2024-04-23) + + +### Bug Fixes + +* **YouTube - Hide Shorts components:** Rename option title to make it consistent ([4d6e34b](https://github.com/ReVanced/revanced-patches/commit/4d6e34b0540a3334bd77b2b48a1a5e10329171c8)) + +# [4.8.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.3...v4.8.0-dev.4) (2024-04-23) + + +### Features + +* **YouTube - Comments:** Add option to hide timestamp and emoji buttons ([#3076](https://github.com/ReVanced/revanced-patches/issues/3076)) ([7efe5ae](https://github.com/ReVanced/revanced-patches/commit/7efe5aefb252a2ed908907ff218b879e2ad1a331)) + +# [4.8.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.2...v4.8.0-dev.3) (2024-04-22) + + +### Bug Fixes + +* Publicize abstract property ([b7c108e](https://github.com/ReVanced/revanced-patches/commit/b7c108ee201c84df31b079f3fecb6cc2f5eaf9f1)) + +# [4.8.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.1...v4.8.0-dev.2) (2024-04-21) + + +### Bug Fixes + +* Case patch option title correctly ([259c8b4](https://github.com/ReVanced/revanced-patches/commit/259c8b4e58df51d92d7e19417e13afa3848afc73)) + +# [4.8.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.7.0...v4.8.0-dev.1) (2024-04-21) + + +### Bug Fixes + +* **YouTube - Hide video action buttons:** Remove obsolete `hide Shop button` ([#3057](https://github.com/ReVanced/revanced-patches/issues/3057)) ([b5e34f3](https://github.com/ReVanced/revanced-patches/commit/b5e34f3aabc1d9df8c41f92251618243caecdc9f)) + + +### Features + +* **YouTube - Hide Shorts components:** Hide like / dislike button in video ads ([#3062](https://github.com/ReVanced/revanced-patches/issues/3062)) ([1296985](https://github.com/ReVanced/revanced-patches/commit/12969853adfe530eb6006df38e1a5aa30b28fdf9)) + # [4.7.0](https://github.com/ReVanced/revanced-patches/compare/v4.6.0...v4.7.0) (2024-04-21) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 70d6ebad5b..ef79cf77f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,7 @@ This document describes how to contribute to ReVanced Patches. ## 📖 Resources to help you get started -* The [documentation](https://github.com/ReVanced/revanced-patcher/tree/docs/docs) contains the fundamentals +* The [documentation](https://github.com/ReVanced/revanced-patcher/tree/main/docs) contains the fundamentals of ReVanced Patcher and how to use ReVanced Patcher to create patches * [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on * [Issues](https://github.com/ReVanced/revanced-patches/issues) are where we keep track of bugs and feature requests diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 6ee21cc71f..672e180885 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -30,6 +30,7 @@ public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggin public final class app/revanced/patches/all/misc/hex/HexPatch : app/revanced/patches/shared/misc/hex/BaseHexPatch { public fun ()V + public fun getReplacements ()Ljava/util/List; } public final class app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch : app/revanced/patcher/patch/ResourcePatch { @@ -486,6 +487,18 @@ public final class app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPat public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/piccomafr/misc/SpoofAndroidDeviceIdPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/piccomafr/misc/SpoofAndroidDeviceIdPatch; + 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/piccomafr/tracking/DisableTrackingPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/piccomafr/tracking/DisableTrackingPatch; + 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/pixiv/ads/HideAdsPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/pixiv/ads/HideAdsPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V @@ -575,6 +588,7 @@ public final class app/revanced/patches/reddit/customclients/joeyforreddit/detec public final class app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V + public fun patchMiscellaneous (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } @@ -677,6 +691,7 @@ public abstract class app/revanced/patches/shared/misc/hex/BaseHexPatch : app/re public fun ()V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V + public abstract fun getReplacements ()Ljava/util/List; } public final class app/revanced/patches/shared/misc/hex/BaseHexPatch$Replacement { @@ -1060,6 +1075,12 @@ public final class app/revanced/patches/tumblr/ads/DisableDashboardAds : app/rev public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/tumblr/annoyances/adfree/DisableAdFreeBannerPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/tumblr/annoyances/adfree/DisableAdFreeBannerPatch; + 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/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V @@ -1610,12 +1631,10 @@ public final class app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDevic public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { - public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch; - 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; - public 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)Lkotlin/Triple; - public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V - public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Triple;)V +public final class app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch; + 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/SpoofSignaturePatch : app/revanced/patcher/patch/BytecodePatch { @@ -1630,6 +1649,14 @@ 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/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; + public 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)Lkotlin/Triple; + public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V + public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Triple;)V +} + public final class app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch; } diff --git a/gradle.properties b/gradle.properties index 9fbff2fe76..eb93da7976 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.7.0 +version = 4.8.0-dev.24 diff --git a/src/main/kotlin/app/revanced/patches/all/misc/hex/HexPatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/hex/HexPatch.kt index 164eaa13a7..7aaee12b47 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/hex/HexPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/hex/HexPatch.kt @@ -19,7 +19,7 @@ class HexPatch : BaseHexPatch() { // Replace the custom option type with a stringArrayOption once the issue is resolved. private val replacementsOption by registerNewPatchOption, List>( key = "replacements", - title = "replacements", + title = "Replacements", description = """ Hexadecimal patterns to search for and replace with another in a target file. diff --git a/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt index c5c3464099..e97251de52 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt @@ -12,8 +12,6 @@ internal object HideGetPremiumFingerprint : MethodFingerprint( listOf( Opcode.IF_NEZ, Opcode.CONST_16, - Opcode.GOTO, - Opcode.NOP, Opcode.INVOKE_VIRTUAL, ), listOf("FEmusic_history", "FEmusic_offline"), diff --git a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt index 09980c6a98..ee7ffbcb8c 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt @@ -13,7 +13,6 @@ internal object PivotBarConstructorFingerprint : MethodFingerprint( Opcode.CHECK_CAST, Opcode.INVOKE_INTERFACE, Opcode.GOTO, - Opcode.NOP, Opcode.IPUT_OBJECT, Opcode.RETURN_VOID, ), diff --git a/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt index d825b4e8d3..45ebf8377c 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt @@ -1,19 +1,10 @@ package app.revanced.patches.music.misc.integrations.fingerprints import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint -import com.android.tools.smali.dexlib2.Opcode internal object ApplicationInitFingerprint : IntegrationsFingerprint( returnType = "V", parameters = emptyList(), - opcodes = listOf( - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.INVOKE_STATIC, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.INVOKE_VIRTUAL - ), strings = listOf("activity"), customFingerprint = { methodDef, _ -> methodDef.name == "onCreate" }, ) diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch.kt index d1c97cdeca..0ea645e52d 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch.kt @@ -14,7 +14,7 @@ import kotlin.random.Random name = "Spoof device ID", description = "Spoofs device ID to mitigate manual bans by developers.", dependencies = [SignatureDetectionPatch::class], - compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])] + compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.37.0"])] ) @Suppress("unused") object SpoofDeviceIdPatch : BytecodePatch( diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/fingerprints/GetDeviceIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/fingerprints/GetDeviceIdFingerprint.kt index ef3e29f68b..fe01d7b59a 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/fingerprints/GetDeviceIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/detection/deviceid/fingerprints/GetDeviceIdFingerprint.kt @@ -1,9 +1,21 @@ package app.revanced.patches.photomath.detection.deviceid.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode internal object GetDeviceIdFingerprint : MethodFingerprint( returnType = "Ljava/lang/String;", - strings = listOf("androidId", "android_id"), + opcodes = listOf( + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IF_NEZ, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + ), parameters = listOf() ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt index 97c42de2bb..cd784ab20d 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt @@ -5,11 +5,9 @@ import com.android.tools.smali.dexlib2.Opcode internal object CheckSignatureFingerprint : MethodFingerprint( strings = listOf( - "packageInfo.signatures", - "currentSignature" + "signatures", ), opcodes = listOf( - Opcode.CONST_STRING, Opcode.CONST_STRING, Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC, diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt index 1475559073..0c6fb66891 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt @@ -13,7 +13,7 @@ import app.revanced.util.exception name = "Hide update popup", description = "Prevents the update popup from showing up.", dependencies = [SignatureDetectionPatch::class], - compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])] + compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.37.0"])] ) @Suppress("unused") object HideUpdatePopupPatch : BytecodePatch( diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt index 8895696cd8..3885c5c235 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt @@ -13,7 +13,7 @@ import app.revanced.patches.photomath.misc.unlock.plus.fingerprints.IsPlusUnlock @Patch( name = "Unlock plus", dependencies = [SignatureDetectionPatch::class, EnableBookpointPatch::class], - compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])] + compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.37.0"])] ) @Suppress("unused") object UnlockPlusPatch : BytecodePatch( diff --git a/src/main/kotlin/app/revanced/patches/piccomafr/misc/SpoofAndroidDeviceIdPatch.kt b/src/main/kotlin/app/revanced/patches/piccomafr/misc/SpoofAndroidDeviceIdPatch.kt new file mode 100644 index 0000000000..a2a9205261 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/piccomafr/misc/SpoofAndroidDeviceIdPatch.kt @@ -0,0 +1,59 @@ +package app.revanced.patches.piccomafr.misc + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption +import app.revanced.patches.piccomafr.misc.fingerprints.GetAndroidIDFingerprint +import app.revanced.util.exception + +@Patch( + name = "Spoof Android device ID", + description = "Spoofs the Android device ID used by the app for account authentication." + + "This can be used to copy the account to another device.", + compatiblePackages = [ + CompatiblePackage( + "com.piccomaeurope.fr", + [ + "6.4.0", + "6.4.1", + "6.4.2", + "6.4.3", + "6.4.4", + "6.4.5", + "6.5.0", + "6.5.1", + "6.5.2", + "6.5.3", + "6.5.4", + "6.6.0", + "6.6.1", + "6.6.2", + ], + ), + ], + use = false, +) +@Suppress("unused") +object SpoofAndroidDeviceIdPatch : BytecodePatch( + setOf(GetAndroidIDFingerprint), +) { + private var androidDeviceId = + stringPatchOption( + key = "android-device-id", + default = "0011223344556677", + title = "Android device ID", + description = "The Android device ID to spoof to.", + required = true, + ) { it!!.matches("[A-Fa-f0-9]{16}".toRegex()) } + + override fun execute(context: BytecodeContext) = GetAndroidIDFingerprint.result?.mutableMethod?.addInstructions( + 0, + """ + const-string v0, "$androidDeviceId" + return-object v0 + """, + ) ?: throw GetAndroidIDFingerprint.exception +} diff --git a/src/main/kotlin/app/revanced/patches/piccomafr/misc/fingerprints/GetAndroidIDFingerprint.kt b/src/main/kotlin/app/revanced/patches/piccomafr/misc/fingerprints/GetAndroidIDFingerprint.kt new file mode 100644 index 0000000000..31e1ca6ab2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/piccomafr/misc/fingerprints/GetAndroidIDFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.piccomafr.misc.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + + +internal object GetAndroidIDFingerprint : MethodFingerprint( + parameters = listOf("Landroid/content/Context"), + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + strings = listOf( + "context", + "android_id" + ), + returnType = "Ljava/lang/String" +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/piccomafr/tracking/DisableTrackingPatch.kt b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/DisableTrackingPatch.kt new file mode 100644 index 0000000000..0830e5a748 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/DisableTrackingPatch.kt @@ -0,0 +1,80 @@ +package app.revanced.patches.piccomafr.tracking + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.piccomafr.tracking.fingerprints.AppMesurementFingerprint +import app.revanced.patches.piccomafr.tracking.fingerprints.FacebookSDKFingerprint +import app.revanced.patches.piccomafr.tracking.fingerprints.FirebaseInstallFingerprint +import app.revanced.util.exception +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.StringReference + +@Patch( + name = "Disable tracking", + description = "Disables tracking by replacing tracking URLs with example.com.", + compatiblePackages = [ + CompatiblePackage( + "com.piccomaeurope.fr", + [ + "6.4.0", + "6.4.1", + "6.4.2", + "6.4.3", + "6.4.4", + "6.4.5", + "6.5.0", + "6.5.1", + "6.5.2", + "6.5.3", + "6.5.4", + "6.6.0", + "6.6.1", + "6.6.2", + ], + ), + ], +) +@Suppress("unused") +object DisableTrackingPatch : BytecodePatch( + setOf(FacebookSDKFingerprint, FirebaseInstallFingerprint, AppMesurementFingerprint), +) { + override fun execute(context: BytecodeContext) { + FacebookSDKFingerprint.result?.mutableMethod?.apply { + getInstructions().filter { instruction -> + instruction.opcode == Opcode.CONST_STRING + }.forEach { instruction -> + instruction as OneRegisterInstruction + + replaceInstruction( + instruction.location.index, + "const-string v${instruction.registerA}, \"example.com\"", + ) + } + } ?: throw FacebookSDKFingerprint.exception + + FirebaseInstallFingerprint.result?.mutableMethod?.apply { + getInstructions().filter { + it.opcode == Opcode.CONST_STRING + }.filter { + it.getReference()?.string == "firebaseinstallations.googleapis.com" + }.forEach { instruction -> + instruction as OneRegisterInstruction + + replaceInstruction( + instruction.location.index, + "const-string v${instruction.registerA}, \"example.com\"", + ) + } + } ?: throw FirebaseInstallFingerprint.exception + + AppMesurementFingerprint.result?.mutableMethod?.addInstruction(0, "return-void") + ?: throw AppMesurementFingerprint.exception + } +} diff --git a/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/AppMesurementFingerprint.kt b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/AppMesurementFingerprint.kt new file mode 100644 index 0000000000..499491a358 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/AppMesurementFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.piccomafr.tracking.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + + +internal object AppMesurementFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + strings = listOf( + "config/app/", + "Fetching remote configuration" + ), + returnType = "V" +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/FacebookSDKFingerprint.kt b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/FacebookSDKFingerprint.kt new file mode 100644 index 0000000000..ff481e814e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/FacebookSDKFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.piccomafr.tracking.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + + +internal object FacebookSDKFingerprint : MethodFingerprint( + accessFlags = AccessFlags.STATIC or AccessFlags.CONSTRUCTOR, + strings = listOf( + "instagram.com", + "facebook.com" + ), + returnType = "V" +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/FirebaseInstallFingerprint.kt b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/FirebaseInstallFingerprint.kt new file mode 100644 index 0000000000..ebaa6c1256 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/piccomafr/tracking/fingerprints/FirebaseInstallFingerprint.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.piccomafr.tracking.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + + +internal object FirebaseInstallFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PRIVATE.value, + strings = listOf( + "https://%s/%s/%s", + "firebaseinstallations.googleapis.com" + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt index ab110821ec..5663a0223e 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt @@ -10,8 +10,10 @@ import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BasicAuthorizationFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction - +import com.android.tools.smali.dexlib2.iface.reference.StringReference @Suppress("unused") object SpoofClientPatch : BaseSpoofClientPatch( @@ -20,8 +22,8 @@ object SpoofClientPatch : BaseSpoofClientPatch( userAgentFingerprints = setOf(GetUserAgentFingerprint), compatiblePackages = setOf( CompatiblePackage("com.andrewshu.android.reddit"), - CompatiblePackage("com.andrewshu.android.redditdonation") - ) + CompatiblePackage("com.andrewshu.android.redditdonation"), + ), ) { override fun Set.patchClientId(context: BytecodeContext) { /** @@ -59,7 +61,23 @@ object SpoofClientPatch : BaseSpoofClientPatch( """ const-string v0, "$userAgent" return-object v0 - """ + """, ) } -} \ No newline at end of file + + override fun Set.patchMiscellaneous(context: BytecodeContext) { + // Reddit messed up and does not append a redirect uri to the authorization url to old.reddit.com/login. + // Replace old.reddit.com with ssl.reddit.com to fix this. + BuildAuthorizationStringFingerprint.result!!.mutableMethod.apply { + val index = indexOfFirstInstruction { + getReference()?.contains("old.reddit.com") == true + } + + val targetRegister = getInstruction(index).registerA + replaceInstruction( + index, + "const-string v$targetRegister, \"https://ssl.reddit.com/api/v1/authorize.compact\"", + ) + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/hex/BaseHexPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/hex/BaseHexPatch.kt index 781444d688..9758483c94 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/hex/BaseHexPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/hex/BaseHexPatch.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.patch.RawResourcePatch import kotlin.math.max abstract class BaseHexPatch : RawResourcePatch() { - internal abstract val replacements: List + abstract val replacements: List override fun execute(context: ResourceContext) { replacements.groupBy { it.targetFilePath }.forEach { (targetFilePath, replacements) -> diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt index 7c461f6ee9..0178ed5af6 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt @@ -8,10 +8,13 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver import app.revanced.patches.shared.misc.integrations.fingerprints.ReVancedUtilsPatchesVersionFingerprint +import app.revanced.util.exception import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method +import java.net.URLDecoder +import java.nio.charset.StandardCharsets import java.util.jar.JarFile abstract class BaseIntegrationsPatch( @@ -73,8 +76,8 @@ abstract class BaseIntegrationsPatch( val urlString = classUrl.toString() if (urlString.startsWith("jar:file:")) { - val end = urlString.indexOf('!') - return urlString.substring("jar:file:".length, end) + val end = urlString.lastIndexOf('!') + return URLDecoder.decode(urlString.substring("jar:file:".length, end), StandardCharsets.UTF_8) } } throw IllegalStateException("Not running from inside a JAR file.") @@ -137,7 +140,7 @@ abstract class BaseIntegrationsPatch( "invoke-static/range { v$contextRegister .. v$contextRegister }, " + "$integrationsDescriptor->setContext(Landroid/content/Context;)V", ) - } ?: throw PatchException("Could not find hook target fingerprint.") + } ?: throw this.exception } interface IHookInsertIndexResolver : (Method) -> Int { diff --git a/src/main/kotlin/app/revanced/patches/tumblr/annoyances/adfree/DisableAdFreeBannerPatch.kt b/src/main/kotlin/app/revanced/patches/tumblr/annoyances/adfree/DisableAdFreeBannerPatch.kt new file mode 100644 index 0000000000..50791fa5db --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tumblr/annoyances/adfree/DisableAdFreeBannerPatch.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.tumblr.annoyances.adfree + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.tumblr.featureflags.OverrideFeatureFlagsPatch + +@Patch( + name = "Disable Ad-Free Banner", + description = "Disables the banner with a frog, prompting you to buy Tumblr Ad-Free.", + dependencies = [OverrideFeatureFlagsPatch::class], + compatiblePackages = [CompatiblePackage("com.tumblr")], +) +@Suppress("unused") +object DisableAdFreeBannerPatch : BytecodePatch(emptySet()) { + override fun execute(context: BytecodeContext) { + // Disable the "AD_FREE_CTA_BANNER" ("Whether or not to show ad free prompt") feature flag. + OverrideFeatureFlagsPatch.addOverride("adFreeCtaBanner", "false") + } +} diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt index 719c65593d..b034444b7a 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt @@ -62,7 +62,17 @@ object SettingsPatch : BytecodePatch( AddResourcesPatch(this::class) PreferenceScreen.MISC.OTHER.addPreferences( - SwitchPreference("revanced_debug") + // The debug setting is shared across multiple apps and the key must be the same. + // But the title and summary must be different, otherwise when the strings file is flattened + // for Crowdin push, Crowdin gets confused by the duplicate keys. + // FIXME: Ideally the shared debug strings are extracted into a common app group + // and then both apps import that. But for now unique unique title and summary keys also works. + SwitchPreference( + key = "revanced_debug", + titleKey = "revanced_twitch_debug_title", + summaryOnKey = "revanced_twitch_debug_summary_on", + summaryOffKey = "revanced_twitch_debug_summary_off" + ) ) // Hook onCreate to handle fragment creation diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/PromoCodeUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/PromoCodeUnlockPatch.kt index 2f40f8aefa..0fb762b339 100644 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/PromoCodeUnlockPatch.kt +++ b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/PromoCodeUnlockPatch.kt @@ -12,7 +12,7 @@ import app.revanced.patches.warnwetter.misc.promocode.fingerprints.PromoCodeUnlo name = "Promo code unlock", description = "Disables the validation of promo code. Any code will work to unlock all features.", dependencies = [FirebaseGetCertPatch::class], - compatiblePackages = [CompatiblePackage("de.dwd.warnapp")] + compatiblePackages = [CompatiblePackage("de.dwd.warnapp", ["4.2.2"])] ) @Suppress("unused") object PromoCodeUnlockPatch : BytecodePatch( @@ -28,4 +28,4 @@ object PromoCodeUnlockPatch : BytecodePatch( """ ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt index 8cc3ed1135..1ef5e77234 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt @@ -34,6 +34,7 @@ object HideAdsResourcePatch : ResourcePatch() { SwitchPreference("revanced_hide_self_sponsor_ads"), SwitchPreference("revanced_hide_products_banner"), SwitchPreference("revanced_hide_shopping_links"), + SwitchPreference("revanced_hide_visit_store_button"), SwitchPreference("revanced_hide_web_search_results"), SwitchPreference("revanced_hide_merchandise_banners"), ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt index deaebe49ce..20757d6e20 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt @@ -65,8 +65,7 @@ object HideButtonsPatch : ResourcePatch() { SwitchPreference("revanced_hide_download_button"), SwitchPreference("revanced_hide_thanks_button"), SwitchPreference("revanced_hide_clip_button"), - SwitchPreference("revanced_hide_playlist_button"), - SwitchPreference("revanced_hide_shop_button") + SwitchPreference("revanced_hide_playlist_button") ), ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt index 1cdbe20d10..73df8d5775 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt @@ -1,6 +1,7 @@ package app.revanced.patches.youtube.layout.buttons.navigation 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.patch.BytecodePatch @@ -12,11 +13,16 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sor import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.ANDROID_AUTOMOTIVE_STRING import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.AddCreateButtonViewFingerprint +import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.CreatePivotBarFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.util.exception +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +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.MethodReference @Patch( name = "Navigation buttons", @@ -49,14 +55,17 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "19.08.36", "19.09.38", "19.10.39", - "19.11.43" + "19.11.43", ], ), ], ) @Suppress("unused") object NavigationButtonsPatch : BytecodePatch( - setOf(AddCreateButtonViewFingerprint), + setOf( + AddCreateButtonViewFingerprint, + CreatePivotBarFingerprint, + ), ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;" @@ -74,6 +83,7 @@ object NavigationButtonsPatch : BytecodePatch( SwitchPreference("revanced_hide_create_button"), SwitchPreference("revanced_hide_subscriptions_button"), SwitchPreference("revanced_switch_create_with_notifications_button"), + SwitchPreference("revanced_hide_navigation_button_labels"), ), ), ) @@ -99,6 +109,21 @@ object NavigationButtonsPatch : BytecodePatch( } } ?: throw AddCreateButtonViewFingerprint.exception + // Hide navigation button labels. + CreatePivotBarFingerprint.result?.mutableMethod?.apply { + val setTextIndex = indexOfFirstInstruction { + getReference()?.name == "setText" + } + + val targetRegister = getInstruction(setTextIndex).registerC + + addInstruction( + setTextIndex, + "invoke-static { v$targetRegister }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideNavigationButtonLabels(Landroid/widget/TextView;)V", + ) + } ?: throw CreatePivotBarFingerprint.exception + // Hook navigation button created, in order to hide them. NavigationBarHookPatch.hookNavigationButtonCreated(INTEGRATIONS_CLASS_DESCRIPTOR) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/CreatePivotBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/CreatePivotBarFingerprint.kt new file mode 100644 index 0000000000..07b32ba2cb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/CreatePivotBarFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.layout.buttons.navigation.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 CreatePivotBarFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + parameters = listOf( + "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;", + "Landroid/widget/TextView;", + "Ljava/lang/CharSequence;", + ), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID, + ), +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt index 9a6ee70e60..789701ba8a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt @@ -58,7 +58,8 @@ object CommentsPatch : ResourcePatch() { "revanced_comments_screen", preferences = setOf( SwitchPreference("revanced_hide_preview_comment"), - SwitchPreference("revanced_hide_comments_section") + SwitchPreference("revanced_hide_comments_section"), + SwitchPreference("revanced_hide_comment_timestamp_and_emoji_buttons") ), sorting = PreferenceScreen.Sorting.UNSORTED ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index 8944dbbf9f..d982760005 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -103,7 +103,6 @@ object HideLayoutComponentsPatch : BytecodePatch( SwitchPreference("revanced_hide_info_panels"), SwitchPreference("revanced_hide_join_membership_button"), SwitchPreference("revanced_hide_medical_panels"), - SwitchPreference("revanced_hide_playables"), SwitchPreference("revanced_hide_quick_actions"), SwitchPreference("revanced_hide_related_videos"), SwitchPreference("revanced_hide_subscribers_community_guidelines"), @@ -122,6 +121,7 @@ object HideLayoutComponentsPatch : BytecodePatch( SwitchPreference("revanced_hide_mix_playlists"), SwitchPreference("revanced_hide_movies_section"), SwitchPreference("revanced_hide_notify_me_button"), + SwitchPreference("revanced_hide_playables"), SwitchPreference("revanced_hide_search_result_recommendations"), SwitchPreference("revanced_hide_search_result_shelf_header"), SwitchPreference("revanced_hide_show_more_button"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt index 9d1d48a906..689df3c7eb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt @@ -63,7 +63,6 @@ object HidePlayerFlyoutMenuPatch : ResourcePatch() { SwitchPreference("revanced_hide_player_flyout_additional_settings"), SwitchPreference("revanced_hide_player_flyout_loop_video"), SwitchPreference("revanced_hide_player_flyout_ambient_mode"), - SwitchPreference("revanced_hide_player_flyout_report"), SwitchPreference("revanced_hide_player_flyout_help"), SwitchPreference("revanced_hide_player_flyout_speed"), SwitchPreference("revanced_hide_player_flyout_lock_screen"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt index 3471c5dfff..1469c21d06 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt @@ -13,11 +13,14 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch import app.revanced.util.exception +import app.revanced.util.getReference import app.revanced.util.indexOfIdResourceOrThrow import app.revanced.util.injectHideViewCall +import com.android.tools.smali.dexlib2.Opcode 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.MethodReference @Patch( name = "Hide Shorts components", @@ -155,17 +158,24 @@ object HideShortsComponentsPatch : BytecodePatch( } private enum class ShortsButtons(private val resourceName: String, private val methodName: String) { + LIKE("reel_dyn_like", "hideLikeButton"), + DISLIKE("reel_dyn_dislike", "hideDislikeButton"), COMMENTS("reel_dyn_comment", "hideShortsCommentsButton"), REMIX("reel_dyn_remix", "hideShortsRemixButton"), - SHARE("reel_dyn_share", "hideShortsShareButton"), - ; + SHARE("reel_dyn_share", "hideShortsShareButton"); fun injectHideCall(method: MutableMethod) { val referencedIndex = method.indexOfIdResourceOrThrow(resourceName) - val setIdIndex = referencedIndex + 1 + val instruction = method.implementation!!.instructions + .subList(referencedIndex, referencedIndex + 20) + .first { + it.opcode == Opcode.INVOKE_VIRTUAL && it.getReference()?.name == "setId" + } + + val setIdIndex = instruction.location.index val viewRegister = method.getInstruction(setIdIndex).registerC - method.injectHideViewCall(setIdIndex, viewRegister, FILTER_CLASS_DESCRIPTOR, methodName) + method.injectHideViewCall(setIdIndex + 1, viewRegister, FILTER_CLASS_DESCRIPTOR, methodName) } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt index 47381c2d57..598ec85804 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt @@ -41,6 +41,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { SwitchPreference("revanced_hide_shorts_shop_button"), SwitchPreference("revanced_hide_shorts_tagged_products"), SwitchPreference("revanced_hide_shorts_search_suggestions"), + SwitchPreference("revanced_hide_shorts_super_thanks_button"), SwitchPreference("revanced_hide_shorts_location_label"), SwitchPreference("revanced_hide_shorts_channel_bar"), SwitchPreference("revanced_hide_shorts_info_panel"), 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 new file mode 100644 index 0000000000..f843c85f55 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt @@ -0,0 +1,335 @@ +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.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.Companion.toMutable +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.settings.SettingsPatch +import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch +import app.revanced.util.getReference +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 = [ + SpoofClientResourcePatch::class, + PlayerResponseMethodHookPatch::class, + SettingsPatch::class, + AddResourcesPatch::class, + UserAgentClientSpoofPatch::class, + PlayerResponseMethodHookPatch::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", + ], + ), + ], +) +object SpoofClientPatch : BytecodePatch( + setOf( + // Client type spoof. + BuildInitPlaybackRequestFingerprint, + BuildPlayerRequestURIFingerprint, + SetPlayerRequestClientTypeFingerprint, + CreatePlayerRequestBodyFingerprint, + + // Storyboard spoof. + StoryboardRendererSpecFingerprint, + PlayerResponseModelImplRecommendedLevelFingerprint, + StoryboardRendererDecoderRecommendedLevelFingerprint, + PlayerResponseModelImplGeneralFingerprint, + StoryboardRendererDecoderSpecFingerprint, + ), +) { + 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;" + + override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences( + PreferenceScreen( + key = "revanced_spoof_client_screen", + sorting = Sorting.UNSORTED, + preferences = setOf( + SwitchPreference("revanced_spoof_client"), + SwitchPreference("revanced_spoof_client_use_ios"), + ), + ), + + ) + + // 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().first { 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) + } + + // 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 requestMessage.clientInfo.clientType and requestMessage.clientInfo.clientVersion to 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 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 + + :disabled + return-void + """, + ) + }, + ) + } + + // endregion + + // region Fix storyboard if Android Testsuite is used. + + PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter( + "$INTEGRATIONS_CLASS_DESCRIPTOR->setPlayerResponseVideoId(" + + "Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;", + ) + + // Hook recommended seekbar thumbnails quality level for regular videos. + StoryboardRendererDecoderRecommendedLevelFingerprint.resultOrThrow().let { + val endIndex = it.scanResult.patternScanResult!!.endIndex + + it.mutableMethod.apply { + val originalValueRegister = + getInstruction(endIndex).registerA + + addInstructions( + endIndex + 1, + """ + invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I + move-result v$originalValueRegister + """, + ) + } + } + + // Hook the recommended precise seeking thumbnails quality. + PlayerResponseModelImplRecommendedLevelFingerprint.resultOrThrow().let { + val endIndex = it.scanResult.patternScanResult!!.endIndex + + it.mutableMethod.apply { + val originalValueRegister = + getInstruction(endIndex).registerA + + addInstructions( + endIndex, + """ + invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I + move-result v$originalValueRegister + """, + ) + } + } + + // TODO: Hook the seekbar recommended level for Shorts to fix Shorts low quality seekbar thumbnails. + + /** + * Hook StoryBoard renderer url. + */ + PlayerResponseModelImplGeneralFingerprint.resultOrThrow().let { + val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex + + it.mutableMethod.apply { + 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 + """, + ) + } + } + + // Hook the seekbar thumbnail decoder, required for Shorts. + StoryboardRendererDecoderSpecFingerprint.resultOrThrow().let { + val storyBoardUrlIndex = it.scanResult.patternScanResult!!.startIndex + 1 + + it.mutableMethod.apply { + val getStoryBoardRegister = getInstruction(storyBoardUrlIndex).registerA + + addInstructions( + storyBoardUrlIndex + 1, + """ + invoke-static { v$getStoryBoardRegister }, ${INTEGRATIONS_CLASS_DESCRIPTOR}->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$getStoryBoardRegister + """, + ) + } + } + + StoryboardRendererSpecFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val storyBoardUrlParams = "p0" + + addInstructions( + 0, + """ + if-nez $storyBoardUrlParams, :ignore + invoke-static { $storyBoardUrlParams }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; + move-result-object $storyBoardUrlParams + :ignore + nop + """, + ) + } + } + + // endregion + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientResourcePatch.kt new file mode 100644 index 0000000000..0de192e3f7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientResourcePatch.kt @@ -0,0 +1,18 @@ +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]) +internal object SpoofClientResourcePatch : ResourcePatch() { + internal var scrubbedPreviewThumbnailResourceId: Long = -1 + + override fun execute(context: ResourceContext) { + scrubbedPreviewThumbnailResourceId = ResourceMappingPatch[ + "id", + "thumbnail", + ] + } +} 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 4e9a7833c4..5593ee72cf 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 @@ -68,7 +68,7 @@ object SpoofSignaturePatch : BytecodePatch( // Hook the player parameters. PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter( - "$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Z)Ljava/lang/String;", + "$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;", ) // Force the seekbar time and chapters to always show up. @@ -104,7 +104,7 @@ object SpoofSignaturePatch : BytecodePatch( } // If storyboard spoofing is turned off, then hide the empty seekbar thumbnail view. - ScrubbedPreviewLayoutFingerprint.result?.apply { + SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.result?.apply { val endIndex = scanResult.patternScanResult!!.endIndex mutableMethod.apply { val imageViewFieldName = getInstruction(endIndex).reference @@ -116,7 +116,7 @@ object SpoofSignaturePatch : BytecodePatch( """, ) } - } ?: throw ScrubbedPreviewLayoutFingerprint.exception + } ?: throw SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.exception /** * Hook StoryBoard renderer url 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 d65e23ee37..c29c94381b 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 @@ -4,9 +4,9 @@ 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 -import app.revanced.patches.youtube.misc.settings.SettingsPatch -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) +@Patch(dependencies = [ResourceMappingPatch::class]) +@Deprecated("This patch will be removed in the future.") object SpoofSignatureResourcePatch : ResourcePatch() { internal var scrubbedPreviewThumbnailResourceId: Long = -1 diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt index aeb1788d74..2c0eaceb38 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch.kt @@ -2,8 +2,6 @@ package app.revanced.patches.youtube.misc.fix.playback import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction -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.patches.all.misc.transformation.BaseTransformInstructionsPatch import app.revanced.patches.all.misc.transformation.IMethodCall @@ -16,14 +14,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference -@Patch( - name = "Client spoof", - description = "Spoofs the client to allow video playback.", - compatiblePackages = [ - CompatiblePackage("com.google.android.youtube"), - ], -) -object ClientSpoofPatch : BaseTransformInstructionsPatch() { +object UserAgentClientSpoofPatch : BaseTransformInstructionsPatch() { private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube" private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE = "Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;" diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildInitPlaybackRequestFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildInitPlaybackRequestFingerprint.kt new file mode 100644 index 0000000000..4b63fd1302 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildInitPlaybackRequestFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object BuildInitPlaybackRequestFingerprint : MethodFingerprint( + returnType = "Lorg/chromium/net/UrlRequest\$Builder;", + opcodes = listOf( + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, // Moves the request URI string to a register to build the request with. + ), + strings = listOf( + "Content-Type", + "Range", + ), +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildPlayerRequestURIFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildPlayerRequestURIFingerprint.kt new file mode 100644 index 0000000000..1cdab0f354 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/BuildPlayerRequestURIFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object BuildPlayerRequestURIFingerprint : MethodFingerprint( + returnType = "Ljava/lang/String;", + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, // Register holds player request URI. + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.MONITOR_EXIT, + Opcode.RETURN_OBJECT, + ), + strings = listOf( + "youtubei/v1", + "key", + "asig", + ), +) 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 new file mode 100644 index 0000000000..5abe29e676 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyFingerprint.kt @@ -0,0 +1,15 @@ +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/PlayerResponseModelImplGeneralFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt index fbf360fb8d..ab4be8915f 100644 --- 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 @@ -1,8 +1,8 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints -import app.revanced.util.containsWideLiteralInstructionValue 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 @@ -13,11 +13,11 @@ internal object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint( opcodes = listOf( Opcode.RETURN_OBJECT, Opcode.CONST_4, - Opcode.RETURN_OBJECT + Opcode.RETURN_OBJECT, ), customFingerprint = handler@{ methodDef, _ -> if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false methodDef.containsWideLiteralInstructionValue(55735497) - } -) \ No newline at end of file + }, +) 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 index 0ee384140d..fbd9b0b82b 100644 --- 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 @@ -1,8 +1,8 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints -import app.revanced.util.containsWideLiteralInstructionValue 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 @@ -13,11 +13,11 @@ internal object PlayerResponseModelImplLiveStreamFingerprint : MethodFingerprint opcodes = listOf( Opcode.RETURN_OBJECT, Opcode.CONST_4, - Opcode.RETURN_OBJECT + 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 index 9dd826bfb2..ee54d77623 100644 --- 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 @@ -1,8 +1,8 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints -import app.revanced.util.containsWideLiteralInstructionValue 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 @@ -13,11 +13,11 @@ internal object PlayerResponseModelImplRecommendedLevelFingerprint : MethodFinge opcodes = listOf( Opcode.SGET_OBJECT, Opcode.IGET, - Opcode.RETURN + Opcode.RETURN, ), customFingerprint = handler@{ methodDef, _ -> if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false methodDef.containsWideLiteralInstructionValue(55735497) - } -) \ No newline at end of file + }, +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt index 2781a67161..08e4865233 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt @@ -1,7 +1,7 @@ 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.patches.youtube.misc.fix.playback.SpoofClientResourcePatch import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -23,5 +23,5 @@ internal object ScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint( 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 } -) \ No newline at end of file + literalSupplier = { SpoofClientResourcePatch.scrubbedPreviewThumbnailResourceId }, +) 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 new file mode 100644 index 0000000000..e9d91e761d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SetPlayerRequestClientTypeFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object SetPlayerRequestClientTypeFingerprint : MethodFingerprint( + strings = listOf("10.29"), + opcodes = listOf( + Opcode.IGET, + Opcode.IPUT, // Sets ClientInfo.clientId. + ), +) 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 new file mode 100644 index 0000000000..90220a1c32 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt @@ -0,0 +1,27 @@ +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 + +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/StoryboardRendererDecoderRecommendedLevelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt index 32dd4b19ae..e56867eaea 100644 --- 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 @@ -17,7 +17,7 @@ internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFin Opcode.MOVE_RESULT_OBJECT, Opcode.IPUT_OBJECT, Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT + Opcode.MOVE_RESULT, ), - strings = listOf("#-1#") + 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 index 5d47a9bcf9..bd934d2a31 100644 --- 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 @@ -6,8 +6,8 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode /** -* Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint]. -*/ + * Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint]. + */ internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, @@ -19,5 +19,5 @@ internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint( Opcode.CONST_4, Opcode.IF_NEZ, ), - strings = listOf("#-1#") + strings = listOf("#-1#"), ) 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 index 8a151246df..172001c53f 100644 --- 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 @@ -14,4 +14,4 @@ internal object StoryboardThumbnailParentFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, returnType = "Landroid/graphics/Bitmap;", strings = listOf("Storyboard regionDecoder.decodeRegion exception - "), -) \ No newline at end of file +) 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 4c9e526ec0..f8fe027d50 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 @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.gms import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch import app.revanced.patches.youtube.layout.buttons.cast.HideCastButtonPatch -import app.revanced.patches.youtube.misc.fix.playback.ClientSpoofPatch +import app.revanced.patches.youtube.misc.fix.playback.SpoofClientPatch import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption @@ -27,13 +27,18 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch( integrationsPatchDependency = IntegrationsPatch::class, dependencies = setOf( HideCastButtonPatch::class, - ClientSpoofPatch::class, + SpoofClientPatch::class, ), gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch, compatiblePackages = setOf( CompatiblePackage( "com.google.android.youtube", setOf( + "18.37.36", + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.43", "18.48.39", "18.49.37", "19.01.34", @@ -46,7 +51,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch( "19.08.36", "19.09.38", "19.10.39", - "19.11.43" + "19.11.43", ), ), ), diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt index 36d0066c6f..dc7f343b90 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt @@ -119,7 +119,7 @@ object VideoInformationPatch : BytecodePatch( // Call before any other video id hooks, // so they can use VideoInformation and check if the video id is for a Short. PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameterBeforeVideoId( - "$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerResponseSignature(Ljava/lang/String;Z)Ljava/lang/String;") + "$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerResponseSignature(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;") /* * Set the video time method diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt index 135779eec2..03711953ab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -24,24 +24,39 @@ object PlayerResponseMethodHookPatch : private const val PARAMETER_PROTO_BUFFER = 3 private const val PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11 - // Temporary 4-bit registers used to pass the parameters to integrations. - private const val REGISTER_VIDEO_ID = 0 - private const val REGISTER_PROTO_BUFFER = 1 - private const val REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = 2 + // Registers used to pass the parameters to integrations. + private var playerResponseMethodCopyRegisters = false + private lateinit var REGISTER_VIDEO_ID : String + private lateinit var REGISTER_PROTO_BUFFER : String + private lateinit var REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING : String private lateinit var playerResponseMethod: MutableMethod - private var numberOfInstructionsAdded = 0 override fun execute(context: BytecodeContext) { playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod ?: throw PlayerParameterBuilderFingerprint.exception + + // On some app targets the method has too many registers pushing the parameters past v15. + // If needed, move the parameters to 4-bit registers so they can be passed to integrations. + playerResponseMethodCopyRegisters = playerResponseMethod.implementation!!.registerCount - + playerResponseMethod.parameterTypes.size + PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING > 15 + + if (playerResponseMethodCopyRegisters) { + REGISTER_VIDEO_ID = "v0" + REGISTER_PROTO_BUFFER = "v1" + REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = "v2" + } else { + REGISTER_VIDEO_ID = "p$PARAMETER_VIDEO_ID" + REGISTER_PROTO_BUFFER = "p$PARAMETER_PROTO_BUFFER" + REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = "p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING" + } } override fun close() { fun hookVideoId(hook: Hook) { playerResponseMethod.addInstruction( - 0, "invoke-static {v$REGISTER_VIDEO_ID, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook" + 0, "invoke-static {$REGISTER_VIDEO_ID, $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook" ) numberOfInstructionsAdded++ } @@ -50,8 +65,8 @@ object PlayerResponseMethodHookPatch : playerResponseMethod.addInstructions( 0, """ - invoke-static {v$REGISTER_PROTO_BUFFER, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook - move-result-object v$REGISTER_PROTO_BUFFER + invoke-static {$REGISTER_PROTO_BUFFER, $REGISTER_VIDEO_ID, $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook + move-result-object $REGISTER_PROTO_BUFFER """ ) numberOfInstructionsAdded += 2 @@ -67,22 +82,22 @@ object PlayerResponseMethodHookPatch : videoIdHooks.forEach(::hookVideoId) beforeVideoIdHooks.forEach(::hookProtoBufferParameter) - // On some app targets the method has too many registers pushing the parameters past v15. - // Move the parameters to 4-bit registers so they can be passed to integrations. - playerResponseMethod.addInstructions( - 0, """ - move-object/from16 v$REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID - move-object/from16 v$REGISTER_PROTO_BUFFER, p$PARAMETER_PROTO_BUFFER - move/from16 v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING + if (playerResponseMethodCopyRegisters) { + playerResponseMethod.addInstructions( + 0, """ + move-object/from16 $REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID + move-object/from16 $REGISTER_PROTO_BUFFER, p$PARAMETER_PROTO_BUFFER + move/from16 $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING """, - ) - numberOfInstructionsAdded += 3 + ) + numberOfInstructionsAdded += 3 - // Move the modified register back. - playerResponseMethod.addInstruction( - numberOfInstructionsAdded, - "move-object/from16 p$PARAMETER_PROTO_BUFFER, v$REGISTER_PROTO_BUFFER" - ) + // Move the modified register back. + playerResponseMethod.addInstruction( + numberOfInstructionsAdded, + "move-object/from16 p$PARAMETER_PROTO_BUFFER, $REGISTER_PROTO_BUFFER" + ) + } } internal abstract class Hook(private val methodDescriptor: String) { diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt index a2ccd3e942..e7297fde61 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt @@ -2,14 +2,18 @@ package app.revanced.patches.youtube.video.videoqualitymenu import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction 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.smali.ExternalLabel import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch +import app.revanced.patches.youtube.video.videoqualitymenu.fingerprints.VideoQualityMenuOptionsFingerprint import app.revanced.patches.youtube.video.videoqualitymenu.fingerprints.VideoQualityMenuViewInflateFingerprint +import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( @@ -50,7 +54,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction ) @Suppress("unused") object RestoreOldVideoQualityMenuPatch : BytecodePatch( - setOf(VideoQualityMenuViewInflateFingerprint) + setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint) ) { private const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;" @@ -60,7 +64,8 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch( override fun execute(context: BytecodeContext) { // region Patch for the old type of the video quality menu. - // Only used when spoofing to old app version. + // Used for regular videos when spoofing to old app version, + // and for the Shorts quality flyout on newer app versions. VideoQualityMenuViewInflateFingerprint.result?.let { it.mutableMethod.apply { @@ -76,6 +81,29 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch( } } + // Force YT to add the 'advanced' quality menu for Shorts. + VideoQualityMenuOptionsFingerprint.resultOrThrow().let { + val result = it.scanResult.patternScanResult!! + val startIndex = result.startIndex + val endIndex = result.endIndex + + it.mutableMethod.apply { + val freeRegister = getInstruction(startIndex).registerA + + // A condition controls whether to show the three or four items quality menu. + // Force the four items quality menu to make the "Advanced" item visible, necessary for the patch. + addInstructionsWithLabels( + startIndex + 1, + """ + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation()Z + move-result v$freeRegister + if-nez v$freeRegister, :includeAdvancedMenu + """, + ExternalLabel("includeAdvancedMenu", getInstruction(endIndex)) + ) + } + } + // endregion // region Patch for the new type of the video quality menu. diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt index 8de2a9b0e5..41e1b8ad22 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt @@ -13,6 +13,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch ) object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() { internal var videoQualityBottomSheetListFragmentTitle = -1L + internal var videoQualityQuickMenuAdvancedMenuDescription = -1L override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) @@ -26,5 +27,10 @@ object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() { "layout", "video_quality_bottom_sheet_list_fragment_title", ] + + videoQualityQuickMenuAdvancedMenuDescription = ResourceMappingPatch[ + "string", + "video_quality_quick_menu_advanced_menu_description" + ] } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuOptionsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuOptionsFingerprint.kt new file mode 100644 index 0000000000..0d1a2cc6dc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuOptionsFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.video.videoqualitymenu.fingerprints + +import app.revanced.patches.youtube.video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object VideoQualityMenuOptionsFingerprint : LiteralValueFingerprint( + accessFlags = AccessFlags.STATIC.value, + parameters = listOf("Landroid/content/Context", "L", "L"), + returnType = "[L", + opcodes = listOf( + Opcode.IF_EQZ, // Check if advanced menu should be shown. + Opcode.NEW_ARRAY, + Opcode.APUT_OBJECT, + Opcode.APUT_OBJECT, + Opcode.APUT_OBJECT, + Opcode.RETURN_OBJECT, + Opcode.CONST_4 // Advanced menu code path. + ), + literalSupplier = { RestoreOldVideoQualityMenuResourcePatch.videoQualityQuickMenuAdvancedMenuDescription } +) \ No newline at end of file diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index f59fcb6124..621b7c43bc 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -171,7 +171,7 @@ Hide channel bar Channel bar is hidden Channel bar is shown - Hide playables + Hide Playables Playables are hidden Playables are shown Hide quick actions in fullscreen @@ -249,7 +249,7 @@ General ads are hidden General ads are shown Hide fullscreen ads - Fullscreen ads are hidden + Fullscreen ads are hidden\n\nThis feature is only available for older devices Fullscreen ads are shown Hide buttoned ads Buttoned ads are hidden @@ -266,13 +266,17 @@ Hide shopping links in video description Shopping links are hidden Shopping links are shown + + Hide the \'Visit store\' button on channel pages + Button is hidden + Button is shown Hide web search results Web search results are hidden Web search results are shown Hide merchandise banners Merchandise banners are hidden Merchandise banners are shown - Could not hide fullscreen ad. Hide setting disabled to prevent issues. + Hide fullscreen ads only works with older devices Hide YouTube Premium promotions @@ -393,11 +397,6 @@ Hide Save to playlist Save to playlist button is hidden Save to playlist button is shown - - Hide Shop - Shop button is hidden - Shop button is shown Hide autoplay button @@ -436,8 +435,11 @@ Subscriptions button is shown Switch Create with Notifications - Create button is switched with Notifications button + Create button is switched with Notifications button\n\nNote: Enabling this also forcibly hides video ads Create button is not switched with Notifications button + Hide navigation button labels + Labels are hidden + Labels are shown Flyout menu @@ -458,11 +460,6 @@ Hide Ambient mode Ambient mode menu is hidden Ambient mode menu is shown - - Hide Report - Report menu is hidden - Report menu is shown Hide Help & feedback Help & feedback menu is hidden @@ -508,6 +505,9 @@ Hide comments section Comment section is hidden Comment section is shown + Hide timestamp and emoji buttons + Comment timestamp and emoji buttons are hidden + Comment timestamp and emoji buttons are shown Hide crowdfunding box @@ -586,6 +586,9 @@ Hide shop button Shop button is hidden Shop button is shown + Hide super thanks button + Super thanks button is hidden + Super thanks button is shown Hide tagged products Tagged products are hidden Tagged products are shown @@ -621,7 +624,7 @@ Hide channel bar Channel bar is hidden Channel bar is shown - Hide Shorts video title + Hide video title Title is hidden Title is shown Hide sound metadata label @@ -861,7 +864,7 @@ Are the times correct? - The segment lasts from %1$02d:%2$02d to %3$02d:%4$02d (%5$d minutes %6$02d seconds)\nIs it ready to submit? + The segment is from\n\n%1$s\nto\n%2$s\n\n(%3$s)\n\nReady to submit? Start must be before the end Mark two locations on the time bar first Preview the segment, and ensure it skips smoothly @@ -904,7 +907,7 @@ Version spoofed Version not spoofed App version will be spoofed to an older version of YouTube.\n\nThis will change the appearance and features of the app, but unknown side effects may occur.\n\nIf later turned off, it is recommended to clear the app data to prevent UI bugs. - Spoof app version target @@ -1082,6 +1085,21 @@ 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 to iOS + Spoof the client to iOS instead of an Android Testsuite + Client is spoofed to an iOS client\n\nSide effects include:\n• 60 fps video may not be available\n• No HDR video\n• Some videos may not load\n• Higher video qualities may be missing + Client is spoofed to an Android Testsuite client (iOS client is used for live streams)\n\nSide effects include:\n• Subtitles are missing\n• Player gestures may not work\n• Low quality Shorts seekbar thumbnails + Spoof client thumbnails not available (API timed out) + Spoof client thumbnails temporarily not available: %s + Spoof app signature @@ -1155,9 +1173,9 @@ Other settings Client-side ads Server-side surestream ads - Debug logging - Debug logs are enabled - Debug logs are disabled + Debug logging + Debug logs are enabled + Debug logs are disabled \ No newline at end of file