chore: Merge branch dev
to main
(#3053)
This commit is contained in:
commit
f56e2128e0
174
CHANGELOG.md
174
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)
|
# [4.7.0](https://github.com/ReVanced/revanced-patches/compare/v4.6.0...v4.7.0) (2024-04-21)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ This document describes how to contribute to ReVanced Patches.
|
||||||
|
|
||||||
## 📖 Resources to help you get started
|
## 📖 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
|
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
|
* [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
|
* [Issues](https://github.com/ReVanced/revanced-patches/issues) are where we keep track of bugs and feature requests
|
||||||
|
|
|
@ -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 final class app/revanced/patches/all/misc/hex/HexPatch : app/revanced/patches/shared/misc/hex/BaseHexPatch {
|
||||||
public fun <init> ()V
|
public fun <init> ()V
|
||||||
|
public fun getReplacements ()Ljava/util/List;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch : app/revanced/patcher/patch/ResourcePatch {
|
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 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 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 static final field INSTANCE Lapp/revanced/patches/pixiv/ads/HideAdsPatch;
|
||||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
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 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 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 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
|
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 <init> ()V
|
public fun <init> ()V
|
||||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)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 {
|
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 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 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 static final field INSTANCE Lapp/revanced/patches/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch;
|
||||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
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 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 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/ClientSpoofPatch;
|
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch;
|
||||||
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 execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||||
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 execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
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/SpoofSignaturePatch : app/revanced/patcher/patch/BytecodePatch {
|
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 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 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;
|
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 4.7.0
|
version = 4.8.0-dev.24
|
||||||
|
|
|
@ -19,7 +19,7 @@ class HexPatch : BaseHexPatch() {
|
||||||
// Replace the custom option type with a stringArrayOption once the issue is resolved.
|
// Replace the custom option type with a stringArrayOption once the issue is resolved.
|
||||||
private val replacementsOption by registerNewPatchOption<PatchClass<*>, List<String>>(
|
private val replacementsOption by registerNewPatchOption<PatchClass<*>, List<String>>(
|
||||||
key = "replacements",
|
key = "replacements",
|
||||||
title = "replacements",
|
title = "Replacements",
|
||||||
description = """
|
description = """
|
||||||
Hexadecimal patterns to search for and replace with another in a target file.
|
Hexadecimal patterns to search for and replace with another in a target file.
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ internal object HideGetPremiumFingerprint : MethodFingerprint(
|
||||||
listOf(
|
listOf(
|
||||||
Opcode.IF_NEZ,
|
Opcode.IF_NEZ,
|
||||||
Opcode.CONST_16,
|
Opcode.CONST_16,
|
||||||
Opcode.GOTO,
|
|
||||||
Opcode.NOP,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
),
|
),
|
||||||
listOf("FEmusic_history", "FEmusic_offline"),
|
listOf("FEmusic_history", "FEmusic_offline"),
|
||||||
|
|
|
@ -13,7 +13,6 @@ internal object PivotBarConstructorFingerprint : MethodFingerprint(
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.INVOKE_INTERFACE,
|
Opcode.INVOKE_INTERFACE,
|
||||||
Opcode.GOTO,
|
Opcode.GOTO,
|
||||||
Opcode.NOP,
|
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.IPUT_OBJECT,
|
||||||
Opcode.RETURN_VOID,
|
Opcode.RETURN_VOID,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,19 +1,10 @@
|
||||||
package app.revanced.patches.music.misc.integrations.fingerprints
|
package app.revanced.patches.music.misc.integrations.fingerprints
|
||||||
|
|
||||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
|
|
||||||
internal object ApplicationInitFingerprint : IntegrationsFingerprint(
|
internal object ApplicationInitFingerprint : IntegrationsFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
parameters = emptyList(),
|
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"),
|
strings = listOf("activity"),
|
||||||
customFingerprint = { methodDef, _ -> methodDef.name == "onCreate" },
|
customFingerprint = { methodDef, _ -> methodDef.name == "onCreate" },
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,7 @@ import kotlin.random.Random
|
||||||
name = "Spoof device ID",
|
name = "Spoof device ID",
|
||||||
description = "Spoofs device ID to mitigate manual bans by developers.",
|
description = "Spoofs device ID to mitigate manual bans by developers.",
|
||||||
dependencies = [SignatureDetectionPatch::class],
|
dependencies = [SignatureDetectionPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])]
|
compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.37.0"])]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object SpoofDeviceIdPatch : BytecodePatch(
|
object SpoofDeviceIdPatch : BytecodePatch(
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
package app.revanced.patches.photomath.detection.deviceid.fingerprints
|
package app.revanced.patches.photomath.detection.deviceid.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object GetDeviceIdFingerprint : MethodFingerprint(
|
internal object GetDeviceIdFingerprint : MethodFingerprint(
|
||||||
returnType = "Ljava/lang/String;",
|
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()
|
parameters = listOf()
|
||||||
)
|
)
|
|
@ -5,11 +5,9 @@ import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object CheckSignatureFingerprint : MethodFingerprint(
|
internal object CheckSignatureFingerprint : MethodFingerprint(
|
||||||
strings = listOf(
|
strings = listOf(
|
||||||
"packageInfo.signatures",
|
"signatures",
|
||||||
"currentSignature"
|
|
||||||
),
|
),
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.CONST_STRING,
|
|
||||||
Opcode.CONST_STRING,
|
Opcode.CONST_STRING,
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import app.revanced.util.exception
|
||||||
name = "Hide update popup",
|
name = "Hide update popup",
|
||||||
description = "Prevents the update popup from showing up.",
|
description = "Prevents the update popup from showing up.",
|
||||||
dependencies = [SignatureDetectionPatch::class],
|
dependencies = [SignatureDetectionPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])]
|
compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.37.0"])]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object HideUpdatePopupPatch : BytecodePatch(
|
object HideUpdatePopupPatch : BytecodePatch(
|
||||||
|
|
|
@ -13,7 +13,7 @@ import app.revanced.patches.photomath.misc.unlock.plus.fingerprints.IsPlusUnlock
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Unlock plus",
|
name = "Unlock plus",
|
||||||
dependencies = [SignatureDetectionPatch::class, EnableBookpointPatch::class],
|
dependencies = [SignatureDetectionPatch::class, EnableBookpointPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])]
|
compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.37.0"])]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object UnlockPlusPatch : BytecodePatch(
|
object UnlockPlusPatch : BytecodePatch(
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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"
|
||||||
|
)
|
|
@ -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<StringReference>()?.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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
)
|
|
@ -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"
|
||||||
|
)
|
|
@ -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"
|
||||||
|
)
|
||||||
|
)
|
|
@ -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.BasicAuthorizationFingerprint
|
||||||
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint
|
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint
|
||||||
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint
|
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.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object SpoofClientPatch : BaseSpoofClientPatch(
|
object SpoofClientPatch : BaseSpoofClientPatch(
|
||||||
|
@ -20,8 +22,8 @@ object SpoofClientPatch : BaseSpoofClientPatch(
|
||||||
userAgentFingerprints = setOf(GetUserAgentFingerprint),
|
userAgentFingerprints = setOf(GetUserAgentFingerprint),
|
||||||
compatiblePackages = setOf(
|
compatiblePackages = setOf(
|
||||||
CompatiblePackage("com.andrewshu.android.reddit"),
|
CompatiblePackage("com.andrewshu.android.reddit"),
|
||||||
CompatiblePackage("com.andrewshu.android.redditdonation")
|
CompatiblePackage("com.andrewshu.android.redditdonation"),
|
||||||
)
|
),
|
||||||
) {
|
) {
|
||||||
override fun Set<MethodFingerprintResult>.patchClientId(context: BytecodeContext) {
|
override fun Set<MethodFingerprintResult>.patchClientId(context: BytecodeContext) {
|
||||||
/**
|
/**
|
||||||
|
@ -59,7 +61,23 @@ object SpoofClientPatch : BaseSpoofClientPatch(
|
||||||
"""
|
"""
|
||||||
const-string v0, "$userAgent"
|
const-string v0, "$userAgent"
|
||||||
return-object v0
|
return-object v0
|
||||||
"""
|
""",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun Set<MethodFingerprintResult>.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<StringReference>()?.contains("old.reddit.com") == true
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetRegister = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
replaceInstruction(
|
||||||
|
index,
|
||||||
|
"const-string v$targetRegister, \"https://ssl.reddit.com/api/v1/authorize.compact\"",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import app.revanced.patcher.patch.RawResourcePatch
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
abstract class BaseHexPatch : RawResourcePatch() {
|
abstract class BaseHexPatch : RawResourcePatch() {
|
||||||
internal abstract val replacements: List<Replacement>
|
abstract val replacements: List<Replacement>
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
replacements.groupBy { it.targetFilePath }.forEach { (targetFilePath, replacements) ->
|
replacements.groupBy { it.targetFilePath }.forEach { (targetFilePath, replacements) ->
|
||||||
|
|
|
@ -8,10 +8,13 @@ import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchException
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
|
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
|
||||||
import app.revanced.patches.shared.misc.integrations.fingerprints.ReVancedUtilsPatchesVersionFingerprint
|
import app.revanced.patches.shared.misc.integrations.fingerprints.ReVancedUtilsPatchesVersionFingerprint
|
||||||
|
import app.revanced.util.exception
|
||||||
import app.revanced.util.resultOrThrow
|
import app.revanced.util.resultOrThrow
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import java.net.URLDecoder
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
|
|
||||||
abstract class BaseIntegrationsPatch(
|
abstract class BaseIntegrationsPatch(
|
||||||
|
@ -73,8 +76,8 @@ abstract class BaseIntegrationsPatch(
|
||||||
val urlString = classUrl.toString()
|
val urlString = classUrl.toString()
|
||||||
|
|
||||||
if (urlString.startsWith("jar:file:")) {
|
if (urlString.startsWith("jar:file:")) {
|
||||||
val end = urlString.indexOf('!')
|
val end = urlString.lastIndexOf('!')
|
||||||
return urlString.substring("jar:file:".length, end)
|
return URLDecoder.decode(urlString.substring("jar:file:".length, end), StandardCharsets.UTF_8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Not running from inside a JAR file.")
|
throw IllegalStateException("Not running from inside a JAR file.")
|
||||||
|
@ -137,7 +140,7 @@ abstract class BaseIntegrationsPatch(
|
||||||
"invoke-static/range { v$contextRegister .. v$contextRegister }, " +
|
"invoke-static/range { v$contextRegister .. v$contextRegister }, " +
|
||||||
"$integrationsDescriptor->setContext(Landroid/content/Context;)V",
|
"$integrationsDescriptor->setContext(Landroid/content/Context;)V",
|
||||||
)
|
)
|
||||||
} ?: throw PatchException("Could not find hook target fingerprint.")
|
} ?: throw this.exception
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IHookInsertIndexResolver : (Method) -> Int {
|
interface IHookInsertIndexResolver : (Method) -> Int {
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,7 +62,17 @@ object SettingsPatch : BytecodePatch(
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
PreferenceScreen.MISC.OTHER.addPreferences(
|
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
|
// Hook onCreate to handle fragment creation
|
||||||
|
|
|
@ -12,7 +12,7 @@ import app.revanced.patches.warnwetter.misc.promocode.fingerprints.PromoCodeUnlo
|
||||||
name = "Promo code unlock",
|
name = "Promo code unlock",
|
||||||
description = "Disables the validation of promo code. Any code will work to unlock all features.",
|
description = "Disables the validation of promo code. Any code will work to unlock all features.",
|
||||||
dependencies = [FirebaseGetCertPatch::class],
|
dependencies = [FirebaseGetCertPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("de.dwd.warnapp")]
|
compatiblePackages = [CompatiblePackage("de.dwd.warnapp", ["4.2.2"])]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object PromoCodeUnlockPatch : BytecodePatch(
|
object PromoCodeUnlockPatch : BytecodePatch(
|
||||||
|
|
|
@ -34,6 +34,7 @@ object HideAdsResourcePatch : ResourcePatch() {
|
||||||
SwitchPreference("revanced_hide_self_sponsor_ads"),
|
SwitchPreference("revanced_hide_self_sponsor_ads"),
|
||||||
SwitchPreference("revanced_hide_products_banner"),
|
SwitchPreference("revanced_hide_products_banner"),
|
||||||
SwitchPreference("revanced_hide_shopping_links"),
|
SwitchPreference("revanced_hide_shopping_links"),
|
||||||
|
SwitchPreference("revanced_hide_visit_store_button"),
|
||||||
SwitchPreference("revanced_hide_web_search_results"),
|
SwitchPreference("revanced_hide_web_search_results"),
|
||||||
SwitchPreference("revanced_hide_merchandise_banners"),
|
SwitchPreference("revanced_hide_merchandise_banners"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -65,8 +65,7 @@ object HideButtonsPatch : ResourcePatch() {
|
||||||
SwitchPreference("revanced_hide_download_button"),
|
SwitchPreference("revanced_hide_download_button"),
|
||||||
SwitchPreference("revanced_hide_thanks_button"),
|
SwitchPreference("revanced_hide_thanks_button"),
|
||||||
SwitchPreference("revanced_hide_clip_button"),
|
SwitchPreference("revanced_hide_clip_button"),
|
||||||
SwitchPreference("revanced_hide_playlist_button"),
|
SwitchPreference("revanced_hide_playlist_button")
|
||||||
SwitchPreference("revanced_hide_shop_button")
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package app.revanced.patches.youtube.layout.buttons.navigation
|
package app.revanced.patches.youtube.layout.buttons.navigation
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
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.addInstructions
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
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.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.ANDROID_AUTOMOTIVE_STRING
|
||||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.AddCreateButtonViewFingerprint
|
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.integrations.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
import app.revanced.util.exception
|
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.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Navigation buttons",
|
name = "Navigation buttons",
|
||||||
|
@ -49,14 +55,17 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
"19.08.36",
|
"19.08.36",
|
||||||
"19.09.38",
|
"19.09.38",
|
||||||
"19.10.39",
|
"19.10.39",
|
||||||
"19.11.43"
|
"19.11.43",
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object NavigationButtonsPatch : BytecodePatch(
|
object NavigationButtonsPatch : BytecodePatch(
|
||||||
setOf(AddCreateButtonViewFingerprint),
|
setOf(
|
||||||
|
AddCreateButtonViewFingerprint,
|
||||||
|
CreatePivotBarFingerprint,
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;"
|
"Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;"
|
||||||
|
@ -74,6 +83,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
SwitchPreference("revanced_hide_create_button"),
|
SwitchPreference("revanced_hide_create_button"),
|
||||||
SwitchPreference("revanced_hide_subscriptions_button"),
|
SwitchPreference("revanced_hide_subscriptions_button"),
|
||||||
SwitchPreference("revanced_switch_create_with_notifications_button"),
|
SwitchPreference("revanced_switch_create_with_notifications_button"),
|
||||||
|
SwitchPreference("revanced_hide_navigation_button_labels"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -99,6 +109,21 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
}
|
}
|
||||||
} ?: throw AddCreateButtonViewFingerprint.exception
|
} ?: throw AddCreateButtonViewFingerprint.exception
|
||||||
|
|
||||||
|
// Hide navigation button labels.
|
||||||
|
CreatePivotBarFingerprint.result?.mutableMethod?.apply {
|
||||||
|
val setTextIndex = indexOfFirstInstruction {
|
||||||
|
getReference<MethodReference>()?.name == "setText"
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetRegister = getInstruction<FiveRegisterInstruction>(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.
|
// Hook navigation button created, in order to hide them.
|
||||||
NavigationBarHookPatch.hookNavigationButtonCreated(INTEGRATIONS_CLASS_DESCRIPTOR)
|
NavigationBarHookPatch.hookNavigationButtonCreated(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
|
)
|
|
@ -58,7 +58,8 @@ object CommentsPatch : ResourcePatch() {
|
||||||
"revanced_comments_screen",
|
"revanced_comments_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_hide_preview_comment"),
|
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
|
sorting = PreferenceScreen.Sorting.UNSORTED
|
||||||
)
|
)
|
||||||
|
|
|
@ -103,7 +103,6 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||||
SwitchPreference("revanced_hide_info_panels"),
|
SwitchPreference("revanced_hide_info_panels"),
|
||||||
SwitchPreference("revanced_hide_join_membership_button"),
|
SwitchPreference("revanced_hide_join_membership_button"),
|
||||||
SwitchPreference("revanced_hide_medical_panels"),
|
SwitchPreference("revanced_hide_medical_panels"),
|
||||||
SwitchPreference("revanced_hide_playables"),
|
|
||||||
SwitchPreference("revanced_hide_quick_actions"),
|
SwitchPreference("revanced_hide_quick_actions"),
|
||||||
SwitchPreference("revanced_hide_related_videos"),
|
SwitchPreference("revanced_hide_related_videos"),
|
||||||
SwitchPreference("revanced_hide_subscribers_community_guidelines"),
|
SwitchPreference("revanced_hide_subscribers_community_guidelines"),
|
||||||
|
@ -122,6 +121,7 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||||
SwitchPreference("revanced_hide_mix_playlists"),
|
SwitchPreference("revanced_hide_mix_playlists"),
|
||||||
SwitchPreference("revanced_hide_movies_section"),
|
SwitchPreference("revanced_hide_movies_section"),
|
||||||
SwitchPreference("revanced_hide_notify_me_button"),
|
SwitchPreference("revanced_hide_notify_me_button"),
|
||||||
|
SwitchPreference("revanced_hide_playables"),
|
||||||
SwitchPreference("revanced_hide_search_result_recommendations"),
|
SwitchPreference("revanced_hide_search_result_recommendations"),
|
||||||
SwitchPreference("revanced_hide_search_result_shelf_header"),
|
SwitchPreference("revanced_hide_search_result_shelf_header"),
|
||||||
SwitchPreference("revanced_hide_show_more_button"),
|
SwitchPreference("revanced_hide_show_more_button"),
|
||||||
|
|
|
@ -63,7 +63,6 @@ object HidePlayerFlyoutMenuPatch : ResourcePatch() {
|
||||||
SwitchPreference("revanced_hide_player_flyout_additional_settings"),
|
SwitchPreference("revanced_hide_player_flyout_additional_settings"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_loop_video"),
|
SwitchPreference("revanced_hide_player_flyout_loop_video"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_ambient_mode"),
|
SwitchPreference("revanced_hide_player_flyout_ambient_mode"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_report"),
|
|
||||||
SwitchPreference("revanced_hide_player_flyout_help"),
|
SwitchPreference("revanced_hide_player_flyout_help"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_speed"),
|
SwitchPreference("revanced_hide_player_flyout_speed"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_lock_screen"),
|
SwitchPreference("revanced_hide_player_flyout_lock_screen"),
|
||||||
|
|
|
@ -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.litho.filter.LithoFilterPatch
|
||||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||||
import app.revanced.util.exception
|
import app.revanced.util.exception
|
||||||
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfIdResourceOrThrow
|
import app.revanced.util.indexOfIdResourceOrThrow
|
||||||
import app.revanced.util.injectHideViewCall
|
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.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
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.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Hide Shorts components",
|
name = "Hide Shorts components",
|
||||||
|
@ -155,17 +158,24 @@ object HideShortsComponentsPatch : BytecodePatch(
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class ShortsButtons(private val resourceName: String, private val methodName: String) {
|
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"),
|
COMMENTS("reel_dyn_comment", "hideShortsCommentsButton"),
|
||||||
REMIX("reel_dyn_remix", "hideShortsRemixButton"),
|
REMIX("reel_dyn_remix", "hideShortsRemixButton"),
|
||||||
SHARE("reel_dyn_share", "hideShortsShareButton"),
|
SHARE("reel_dyn_share", "hideShortsShareButton");
|
||||||
;
|
|
||||||
|
|
||||||
fun injectHideCall(method: MutableMethod) {
|
fun injectHideCall(method: MutableMethod) {
|
||||||
val referencedIndex = method.indexOfIdResourceOrThrow(resourceName)
|
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<MethodReference>()?.name == "setId"
|
||||||
|
}
|
||||||
|
|
||||||
|
val setIdIndex = instruction.location.index
|
||||||
val viewRegister = method.getInstruction<FiveRegisterInstruction>(setIdIndex).registerC
|
val viewRegister = method.getInstruction<FiveRegisterInstruction>(setIdIndex).registerC
|
||||||
method.injectHideViewCall(setIdIndex, viewRegister, FILTER_CLASS_DESCRIPTOR, methodName)
|
method.injectHideViewCall(setIdIndex + 1, viewRegister, FILTER_CLASS_DESCRIPTOR, methodName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() {
|
||||||
SwitchPreference("revanced_hide_shorts_shop_button"),
|
SwitchPreference("revanced_hide_shorts_shop_button"),
|
||||||
SwitchPreference("revanced_hide_shorts_tagged_products"),
|
SwitchPreference("revanced_hide_shorts_tagged_products"),
|
||||||
SwitchPreference("revanced_hide_shorts_search_suggestions"),
|
SwitchPreference("revanced_hide_shorts_search_suggestions"),
|
||||||
|
SwitchPreference("revanced_hide_shorts_super_thanks_button"),
|
||||||
SwitchPreference("revanced_hide_shorts_location_label"),
|
SwitchPreference("revanced_hide_shorts_location_label"),
|
||||||
SwitchPreference("revanced_hide_shorts_channel_bar"),
|
SwitchPreference("revanced_hide_shorts_channel_bar"),
|
||||||
SwitchPreference("revanced_hide_shorts_info_panel"),
|
SwitchPreference("revanced_hide_shorts_info_panel"),
|
||||||
|
|
|
@ -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<OneRegisterInstruction>(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<FiveRegisterInstruction>(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<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||||
|
}.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
|
||||||
|
|
||||||
|
// Client info object's client type field.
|
||||||
|
val clientInfoClientTypeField = result.mutableMethod
|
||||||
|
.getInstruction(result.scanResult.patternScanResult!!.endIndex)
|
||||||
|
.getReference<FieldReference>() ?: 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<FieldReference>() ?: 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<OneRegisterInstruction>(checkCastIndex)
|
||||||
|
val requestMessageInstanceRegister = checkCastInstruction.registerA
|
||||||
|
clientInfoContainerClassName = checkCastInstruction.getReference<TypeReference>()!!.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<OneRegisterInstruction>(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<OneRegisterInstruction>(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<OneRegisterInstruction>(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<OneRegisterInstruction>(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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,7 +68,7 @@ object SpoofSignaturePatch : BytecodePatch(
|
||||||
|
|
||||||
// Hook the player parameters.
|
// Hook the player parameters.
|
||||||
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter(
|
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.
|
// 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.
|
// If storyboard spoofing is turned off, then hide the empty seekbar thumbnail view.
|
||||||
ScrubbedPreviewLayoutFingerprint.result?.apply {
|
SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.result?.apply {
|
||||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||||
mutableMethod.apply {
|
mutableMethod.apply {
|
||||||
val imageViewFieldName = getInstruction<ReferenceInstruction>(endIndex).reference
|
val imageViewFieldName = getInstruction<ReferenceInstruction>(endIndex).reference
|
||||||
|
@ -116,7 +116,7 @@ object SpoofSignaturePatch : BytecodePatch(
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} ?: throw ScrubbedPreviewLayoutFingerprint.exception
|
} ?: throw SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.exception
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook StoryBoard renderer url
|
* Hook StoryBoard renderer url
|
||||||
|
|
|
@ -4,9 +4,9 @@ import app.revanced.patcher.data.ResourceContext
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
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() {
|
object SpoofSignatureResourcePatch : ResourcePatch() {
|
||||||
internal var scrubbedPreviewThumbnailResourceId: Long = -1
|
internal var scrubbedPreviewThumbnailResourceId: Long = -1
|
||||||
|
|
||||||
|
|
|
@ -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.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
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.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
|
||||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
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.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
@Patch(
|
object UserAgentClientSpoofPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
name = "Client spoof",
|
|
||||||
description = "Spoofs the client to allow video playback.",
|
|
||||||
compatiblePackages = [
|
|
||||||
CompatiblePackage("com.google.android.youtube"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
object ClientSpoofPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
|
||||||
private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube"
|
private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube"
|
||||||
private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE =
|
private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE =
|
||||||
"Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;"
|
"Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;"
|
|
@ -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",
|
||||||
|
),
|
||||||
|
)
|
|
@ -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",
|
||||||
|
),
|
||||||
|
)
|
|
@ -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"),
|
||||||
|
)
|
|
@ -1,8 +1,8 @@
|
||||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
import app.revanced.util.containsWideLiteralInstructionValue
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import app.revanced.util.containsWideLiteralInstructionValue
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ internal object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint(
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.RETURN_OBJECT,
|
Opcode.RETURN_OBJECT,
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.RETURN_OBJECT
|
Opcode.RETURN_OBJECT,
|
||||||
),
|
),
|
||||||
customFingerprint = handler@{ methodDef, _ ->
|
customFingerprint = handler@{ methodDef, _ ->
|
||||||
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
|
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
|
||||||
|
|
||||||
methodDef.containsWideLiteralInstructionValue(55735497)
|
methodDef.containsWideLiteralInstructionValue(55735497)
|
||||||
}
|
},
|
||||||
)
|
)
|
|
@ -1,8 +1,8 @@
|
||||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
import app.revanced.util.containsWideLiteralInstructionValue
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import app.revanced.util.containsWideLiteralInstructionValue
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ internal object PlayerResponseModelImplLiveStreamFingerprint : MethodFingerprint
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.RETURN_OBJECT,
|
Opcode.RETURN_OBJECT,
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.RETURN_OBJECT
|
Opcode.RETURN_OBJECT,
|
||||||
),
|
),
|
||||||
customFingerprint = handler@{ methodDef, _ ->
|
customFingerprint = handler@{ methodDef, _ ->
|
||||||
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
|
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
|
||||||
|
|
||||||
methodDef.containsWideLiteralInstructionValue(70276274)
|
methodDef.containsWideLiteralInstructionValue(70276274)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
import app.revanced.util.containsWideLiteralInstructionValue
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import app.revanced.util.containsWideLiteralInstructionValue
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ internal object PlayerResponseModelImplRecommendedLevelFingerprint : MethodFinge
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.SGET_OBJECT,
|
Opcode.SGET_OBJECT,
|
||||||
Opcode.IGET,
|
Opcode.IGET,
|
||||||
Opcode.RETURN
|
Opcode.RETURN,
|
||||||
),
|
),
|
||||||
customFingerprint = handler@{ methodDef, _ ->
|
customFingerprint = handler@{ methodDef, _ ->
|
||||||
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
|
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
|
||||||
|
|
||||||
methodDef.containsWideLiteralInstructionValue(55735497)
|
methodDef.containsWideLiteralInstructionValue(55735497)
|
||||||
}
|
},
|
||||||
)
|
)
|
|
@ -1,7 +1,7 @@
|
||||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
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 app.revanced.util.patch.LiteralValueFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
@ -23,5 +23,5 @@ internal object ScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint(
|
||||||
Opcode.IPUT_OBJECT, // preview imageview
|
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.
|
// This resource is used in ~ 40 different locations, but this method has a distinct list of parameters to match to.
|
||||||
literalSupplier = { SpoofSignatureResourcePatch.scrubbedPreviewThumbnailResourceId }
|
literalSupplier = { SpoofClientResourcePatch.scrubbedPreviewThumbnailResourceId },
|
||||||
)
|
)
|
|
@ -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.
|
||||||
|
),
|
||||||
|
)
|
|
@ -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 },
|
||||||
|
)
|
|
@ -17,7 +17,7 @@ internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFin
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.IPUT_OBJECT,
|
||||||
Opcode.INVOKE_INTERFACE,
|
Opcode.INVOKE_INTERFACE,
|
||||||
Opcode.MOVE_RESULT
|
Opcode.MOVE_RESULT,
|
||||||
),
|
),
|
||||||
strings = listOf("#-1#")
|
strings = listOf("#-1#"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,5 +19,5 @@ internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint(
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.IF_NEZ,
|
Opcode.IF_NEZ,
|
||||||
),
|
),
|
||||||
strings = listOf("#-1#")
|
strings = listOf("#-1#"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.gms
|
||||||
import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint
|
import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint
|
||||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
||||||
import app.revanced.patches.youtube.layout.buttons.cast.HideCastButtonPatch
|
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.REVANCED_YOUTUBE_PACKAGE_NAME
|
||||||
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
|
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
|
||||||
import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
||||||
|
@ -27,13 +27,18 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||||
integrationsPatchDependency = IntegrationsPatch::class,
|
integrationsPatchDependency = IntegrationsPatch::class,
|
||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
HideCastButtonPatch::class,
|
HideCastButtonPatch::class,
|
||||||
ClientSpoofPatch::class,
|
SpoofClientPatch::class,
|
||||||
),
|
),
|
||||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
||||||
compatiblePackages = setOf(
|
compatiblePackages = setOf(
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube",
|
"com.google.android.youtube",
|
||||||
setOf(
|
setOf(
|
||||||
|
"18.37.36",
|
||||||
|
"18.38.44",
|
||||||
|
"18.43.45",
|
||||||
|
"18.44.41",
|
||||||
|
"18.45.43",
|
||||||
"18.48.39",
|
"18.48.39",
|
||||||
"18.49.37",
|
"18.49.37",
|
||||||
"19.01.34",
|
"19.01.34",
|
||||||
|
@ -46,7 +51,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||||
"19.08.36",
|
"19.08.36",
|
||||||
"19.09.38",
|
"19.09.38",
|
||||||
"19.10.39",
|
"19.10.39",
|
||||||
"19.11.43"
|
"19.11.43",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -119,7 +119,7 @@ object VideoInformationPatch : BytecodePatch(
|
||||||
// Call before any other video id hooks,
|
// Call before any other video id hooks,
|
||||||
// so they can use VideoInformation and check if the video id is for a Short.
|
// so they can use VideoInformation and check if the video id is for a Short.
|
||||||
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameterBeforeVideoId(
|
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
|
* Set the video time method
|
||||||
|
|
|
@ -24,24 +24,39 @@ object PlayerResponseMethodHookPatch :
|
||||||
private const val PARAMETER_PROTO_BUFFER = 3
|
private const val PARAMETER_PROTO_BUFFER = 3
|
||||||
private const val PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11
|
private const val PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11
|
||||||
|
|
||||||
// Temporary 4-bit registers used to pass the parameters to integrations.
|
// Registers used to pass the parameters to integrations.
|
||||||
private const val REGISTER_VIDEO_ID = 0
|
private var playerResponseMethodCopyRegisters = false
|
||||||
private const val REGISTER_PROTO_BUFFER = 1
|
private lateinit var REGISTER_VIDEO_ID : String
|
||||||
private const val REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = 2
|
private lateinit var REGISTER_PROTO_BUFFER : String
|
||||||
|
private lateinit var REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING : String
|
||||||
|
|
||||||
private lateinit var playerResponseMethod: MutableMethod
|
private lateinit var playerResponseMethod: MutableMethod
|
||||||
|
|
||||||
private var numberOfInstructionsAdded = 0
|
private var numberOfInstructionsAdded = 0
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod
|
playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod
|
||||||
?: throw PlayerParameterBuilderFingerprint.exception
|
?: 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() {
|
override fun close() {
|
||||||
fun hookVideoId(hook: Hook) {
|
fun hookVideoId(hook: Hook) {
|
||||||
playerResponseMethod.addInstruction(
|
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++
|
numberOfInstructionsAdded++
|
||||||
}
|
}
|
||||||
|
@ -50,8 +65,8 @@ object PlayerResponseMethodHookPatch :
|
||||||
playerResponseMethod.addInstructions(
|
playerResponseMethod.addInstructions(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
invoke-static {v$REGISTER_PROTO_BUFFER, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
|
invoke-static {$REGISTER_PROTO_BUFFER, $REGISTER_VIDEO_ID, $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
|
||||||
move-result-object v$REGISTER_PROTO_BUFFER
|
move-result-object $REGISTER_PROTO_BUFFER
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
numberOfInstructionsAdded += 2
|
numberOfInstructionsAdded += 2
|
||||||
|
@ -67,13 +82,12 @@ object PlayerResponseMethodHookPatch :
|
||||||
videoIdHooks.forEach(::hookVideoId)
|
videoIdHooks.forEach(::hookVideoId)
|
||||||
beforeVideoIdHooks.forEach(::hookProtoBufferParameter)
|
beforeVideoIdHooks.forEach(::hookProtoBufferParameter)
|
||||||
|
|
||||||
// On some app targets the method has too many registers pushing the parameters past v15.
|
if (playerResponseMethodCopyRegisters) {
|
||||||
// Move the parameters to 4-bit registers so they can be passed to integrations.
|
|
||||||
playerResponseMethod.addInstructions(
|
playerResponseMethod.addInstructions(
|
||||||
0, """
|
0, """
|
||||||
move-object/from16 v$REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID
|
move-object/from16 $REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID
|
||||||
move-object/from16 v$REGISTER_PROTO_BUFFER, p$PARAMETER_PROTO_BUFFER
|
move-object/from16 $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
|
move/from16 $REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
numberOfInstructionsAdded += 3
|
numberOfInstructionsAdded += 3
|
||||||
|
@ -81,9 +95,10 @@ object PlayerResponseMethodHookPatch :
|
||||||
// Move the modified register back.
|
// Move the modified register back.
|
||||||
playerResponseMethod.addInstruction(
|
playerResponseMethod.addInstruction(
|
||||||
numberOfInstructionsAdded,
|
numberOfInstructionsAdded,
|
||||||
"move-object/from16 p$PARAMETER_PROTO_BUFFER, v$REGISTER_PROTO_BUFFER"
|
"move-object/from16 p$PARAMETER_PROTO_BUFFER, $REGISTER_PROTO_BUFFER"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal abstract class Hook(private val methodDescriptor: String) {
|
internal abstract class Hook(private val methodDescriptor: String) {
|
||||||
internal class VideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
internal class VideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||||
|
|
|
@ -2,14 +2,18 @@ package app.revanced.patches.youtube.video.videoqualitymenu
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
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.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
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.integrations.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
||||||
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch
|
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.patches.youtube.video.videoqualitymenu.fingerprints.VideoQualityMenuViewInflateFingerprint
|
||||||
|
import app.revanced.util.resultOrThrow
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
|
@ -50,7 +54,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object RestoreOldVideoQualityMenuPatch : BytecodePatch(
|
object RestoreOldVideoQualityMenuPatch : BytecodePatch(
|
||||||
setOf(VideoQualityMenuViewInflateFingerprint)
|
setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint)
|
||||||
) {
|
) {
|
||||||
private const val FILTER_CLASS_DESCRIPTOR =
|
private const val FILTER_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;"
|
"Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;"
|
||||||
|
@ -60,7 +64,8 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
// region Patch for the old type of the video quality menu.
|
// 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 {
|
VideoQualityMenuViewInflateFingerprint.result?.let {
|
||||||
it.mutableMethod.apply {
|
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<OneRegisterInstruction>(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
|
// endregion
|
||||||
|
|
||||||
// region Patch for the new type of the video quality menu.
|
// region Patch for the new type of the video quality menu.
|
||||||
|
|
|
@ -13,6 +13,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
)
|
)
|
||||||
object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() {
|
object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() {
|
||||||
internal var videoQualityBottomSheetListFragmentTitle = -1L
|
internal var videoQualityBottomSheetListFragmentTitle = -1L
|
||||||
|
internal var videoQualityQuickMenuAdvancedMenuDescription = -1L
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
@ -26,5 +27,10 @@ object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() {
|
||||||
"layout",
|
"layout",
|
||||||
"video_quality_bottom_sheet_list_fragment_title",
|
"video_quality_bottom_sheet_list_fragment_title",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
videoQualityQuickMenuAdvancedMenuDescription = ResourceMappingPatch[
|
||||||
|
"string",
|
||||||
|
"video_quality_quick_menu_advanced_menu_description"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 }
|
||||||
|
)
|
|
@ -171,7 +171,7 @@
|
||||||
<string name="revanced_hide_channel_bar_title">Hide channel bar</string>
|
<string name="revanced_hide_channel_bar_title">Hide channel bar</string>
|
||||||
<string name="revanced_hide_channel_bar_summary_on">Channel bar is hidden</string>
|
<string name="revanced_hide_channel_bar_summary_on">Channel bar is hidden</string>
|
||||||
<string name="revanced_hide_channel_bar_summary_off">Channel bar is shown</string>
|
<string name="revanced_hide_channel_bar_summary_off">Channel bar is shown</string>
|
||||||
<string name="revanced_hide_playables_title">Hide playables</string>
|
<string name="revanced_hide_playables_title">Hide Playables</string>
|
||||||
<string name="revanced_hide_playables_summary_on">Playables are hidden</string>
|
<string name="revanced_hide_playables_summary_on">Playables are hidden</string>
|
||||||
<string name="revanced_hide_playables_summary_off">Playables are shown</string>
|
<string name="revanced_hide_playables_summary_off">Playables are shown</string>
|
||||||
<string name="revanced_hide_quick_actions_title">Hide quick actions in fullscreen</string>
|
<string name="revanced_hide_quick_actions_title">Hide quick actions in fullscreen</string>
|
||||||
|
@ -249,7 +249,7 @@
|
||||||
<string name="revanced_hide_general_ads_summary_on">General ads are hidden</string>
|
<string name="revanced_hide_general_ads_summary_on">General ads are hidden</string>
|
||||||
<string name="revanced_hide_general_ads_summary_off">General ads are shown</string>
|
<string name="revanced_hide_general_ads_summary_off">General ads are shown</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_title">Hide fullscreen ads</string>
|
<string name="revanced_hide_fullscreen_ads_title">Hide fullscreen ads</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_summary_on">Fullscreen ads are hidden</string>
|
<string name="revanced_hide_fullscreen_ads_summary_on">Fullscreen ads are hidden\n\nThis feature is only available for older devices</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_summary_off">Fullscreen ads are shown</string>
|
<string name="revanced_hide_fullscreen_ads_summary_off">Fullscreen ads are shown</string>
|
||||||
<string name="revanced_hide_buttoned_ads_title">Hide buttoned ads</string>
|
<string name="revanced_hide_buttoned_ads_title">Hide buttoned ads</string>
|
||||||
<string name="revanced_hide_buttoned_ads_summary_on">Buttoned ads are hidden</string>
|
<string name="revanced_hide_buttoned_ads_summary_on">Buttoned ads are hidden</string>
|
||||||
|
@ -266,13 +266,17 @@
|
||||||
<string name="revanced_hide_shopping_links_title">Hide shopping links in video description</string>
|
<string name="revanced_hide_shopping_links_title">Hide shopping links in video description</string>
|
||||||
<string name="revanced_hide_shopping_links_summary_on">Shopping links are hidden</string>
|
<string name="revanced_hide_shopping_links_summary_on">Shopping links are hidden</string>
|
||||||
<string name="revanced_hide_shopping_links_summary_off">Shopping links are shown</string>
|
<string name="revanced_hide_shopping_links_summary_off">Shopping links are shown</string>
|
||||||
|
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
|
||||||
|
<string name="revanced_hide_visit_store_button_title">Hide the \'Visit store\' button on channel pages</string>
|
||||||
|
<string name="revanced_hide_visit_store_button_summary_on">Button is hidden</string>
|
||||||
|
<string name="revanced_hide_visit_store_button_summary_off">Button is shown</string>
|
||||||
<string name="revanced_hide_web_search_results_title">Hide web search results</string>
|
<string name="revanced_hide_web_search_results_title">Hide web search results</string>
|
||||||
<string name="revanced_hide_web_search_results_summary_on">Web search results are hidden</string>
|
<string name="revanced_hide_web_search_results_summary_on">Web search results are hidden</string>
|
||||||
<string name="revanced_hide_web_search_results_summary_off">Web search results are shown</string>
|
<string name="revanced_hide_web_search_results_summary_off">Web search results are shown</string>
|
||||||
<string name="revanced_hide_merchandise_banners_title">Hide merchandise banners</string>
|
<string name="revanced_hide_merchandise_banners_title">Hide merchandise banners</string>
|
||||||
<string name="revanced_hide_merchandise_banners_summary_on">Merchandise banners are hidden</string>
|
<string name="revanced_hide_merchandise_banners_summary_on">Merchandise banners are hidden</string>
|
||||||
<string name="revanced_hide_merchandise_banners_summary_off">Merchandise banners are shown</string>
|
<string name="revanced_hide_merchandise_banners_summary_off">Merchandise banners are shown</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_feature_not_available_toast">Could not hide fullscreen ad. Hide setting disabled to prevent issues.</string>
|
<string name="revanced_hide_fullscreen_ads_feature_not_available_toast">Hide fullscreen ads only works with older devices</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="ad.getpremium.HideGetPremiumPatch">
|
<patch id="ad.getpremium.HideGetPremiumPatch">
|
||||||
<string name="revanced_hide_get_premium_title">Hide YouTube Premium promotions</string>
|
<string name="revanced_hide_get_premium_title">Hide YouTube Premium promotions</string>
|
||||||
|
@ -393,11 +397,6 @@
|
||||||
<string name="revanced_hide_playlist_button_title">Hide Save to playlist</string>
|
<string name="revanced_hide_playlist_button_title">Hide Save to playlist</string>
|
||||||
<string name="revanced_hide_playlist_button_summary_on">Save to playlist button is hidden</string>
|
<string name="revanced_hide_playlist_button_summary_on">Save to playlist button is hidden</string>
|
||||||
<string name="revanced_hide_playlist_button_summary_off">Save to playlist button is shown</string>
|
<string name="revanced_hide_playlist_button_summary_off">Save to playlist button is shown</string>
|
||||||
<!-- 'Shop' should be translated with the same localized wording that YouTube displays.
|
|
||||||
Shop button appears only for some videos in certain regions. Translate the button name normally if this menu is never shown. -->
|
|
||||||
<string name="revanced_hide_shop_button_title">Hide Shop</string>
|
|
||||||
<string name="revanced_hide_shop_button_summary_on">Shop button is hidden</string>
|
|
||||||
<string name="revanced_hide_shop_button_summary_off">Shop button is shown</string>
|
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
|
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
|
||||||
<string name="revanced_hide_autoplay_button_title">Hide autoplay button</string>
|
<string name="revanced_hide_autoplay_button_title">Hide autoplay button</string>
|
||||||
|
@ -436,8 +435,11 @@
|
||||||
<string name="revanced_hide_subscriptions_button_summary_off">Subscriptions button is shown</string>
|
<string name="revanced_hide_subscriptions_button_summary_off">Subscriptions button is shown</string>
|
||||||
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
|
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
|
||||||
<string name="revanced_switch_create_with_notifications_button_title">Switch Create with Notifications</string>
|
<string name="revanced_switch_create_with_notifications_button_title">Switch Create with Notifications</string>
|
||||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Create button is switched with Notifications button</string>
|
<string name="revanced_switch_create_with_notifications_button_summary_on">Create button is switched with Notifications button\n\nNote: Enabling this also forcibly hides video ads</string>
|
||||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Create button is not switched with Notifications button</string>
|
<string name="revanced_switch_create_with_notifications_button_summary_off">Create button is not switched with Notifications button</string>
|
||||||
|
<string name="revanced_hide_navigation_button_labels_title">Hide navigation button labels</string>
|
||||||
|
<string name="revanced_hide_navigation_button_labels_summary_on">Labels are hidden</string>
|
||||||
|
<string name="revanced_hide_navigation_button_labels_summary_off">Labels are shown</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
|
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
|
||||||
<string name="revanced_hide_player_flyout_title">Flyout menu</string>
|
<string name="revanced_hide_player_flyout_title">Flyout menu</string>
|
||||||
|
@ -458,11 +460,6 @@
|
||||||
<string name="revanced_hide_player_flyout_ambient_mode_title">Hide Ambient mode</string>
|
<string name="revanced_hide_player_flyout_ambient_mode_title">Hide Ambient mode</string>
|
||||||
<string name="revanced_hide_player_flyout_ambient_mode_summary_on">Ambient mode menu is hidden</string>
|
<string name="revanced_hide_player_flyout_ambient_mode_summary_on">Ambient mode menu is hidden</string>
|
||||||
<string name="revanced_hide_player_flyout_ambient_mode_summary_off">Ambient mode menu is shown</string>
|
<string name="revanced_hide_player_flyout_ambient_mode_summary_off">Ambient mode menu is shown</string>
|
||||||
<!-- 'Report' should be translated using the same localized wording YouTube displays for the menu item.
|
|
||||||
This item may not appear in some regions. Translate the name normally if the menu cannot be found. -->
|
|
||||||
<string name="revanced_hide_player_flyout_report_title">Hide Report</string>
|
|
||||||
<string name="revanced_hide_player_flyout_report_summary_on">Report menu is hidden</string>
|
|
||||||
<string name="revanced_hide_player_flyout_report_summary_off">Report menu is shown</string>
|
|
||||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||||
<string name="revanced_hide_player_flyout_help_title">Hide Help & feedback</string>
|
<string name="revanced_hide_player_flyout_help_title">Hide Help & feedback</string>
|
||||||
<string name="revanced_hide_player_flyout_help_summary_on">Help & feedback menu is hidden</string>
|
<string name="revanced_hide_player_flyout_help_summary_on">Help & feedback menu is hidden</string>
|
||||||
|
@ -508,6 +505,9 @@
|
||||||
<string name="revanced_hide_comments_section_title">Hide comments section</string>
|
<string name="revanced_hide_comments_section_title">Hide comments section</string>
|
||||||
<string name="revanced_hide_comments_section_summary_on">Comment section is hidden</string>
|
<string name="revanced_hide_comments_section_summary_on">Comment section is hidden</string>
|
||||||
<string name="revanced_hide_comments_section_summary_off">Comment section is shown</string>
|
<string name="revanced_hide_comments_section_summary_off">Comment section is shown</string>
|
||||||
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_title">Hide timestamp and emoji buttons</string>
|
||||||
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary_on">Comment timestamp and emoji buttons are hidden</string>
|
||||||
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary_off">Comment timestamp and emoji buttons are shown</string>
|
||||||
</patch>
|
</patch>
|
||||||
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
|
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
|
||||||
<string name="revanced_hide_crowdfunding_box_title">Hide crowdfunding box</string>
|
<string name="revanced_hide_crowdfunding_box_title">Hide crowdfunding box</string>
|
||||||
|
@ -586,6 +586,9 @@
|
||||||
<string name="revanced_hide_shorts_shop_button_title">Hide shop button</string>
|
<string name="revanced_hide_shorts_shop_button_title">Hide shop button</string>
|
||||||
<string name="revanced_hide_shorts_shop_button_summary_on">Shop button is hidden</string>
|
<string name="revanced_hide_shorts_shop_button_summary_on">Shop button is hidden</string>
|
||||||
<string name="revanced_hide_shorts_shop_button_summary_off">Shop button is shown</string>
|
<string name="revanced_hide_shorts_shop_button_summary_off">Shop button is shown</string>
|
||||||
|
<string name="revanced_hide_shorts_super_thanks_button_title">Hide super thanks button</string>
|
||||||
|
<string name="revanced_hide_shorts_super_thanks_button_summary_on">Super thanks button is hidden</string>
|
||||||
|
<string name="revanced_hide_shorts_super_thanks_button_summary_off">Super thanks button is shown</string>
|
||||||
<string name="revanced_hide_shorts_tagged_products_title">Hide tagged products</string>
|
<string name="revanced_hide_shorts_tagged_products_title">Hide tagged products</string>
|
||||||
<string name="revanced_hide_shorts_tagged_products_summary_on">Tagged products are hidden</string>
|
<string name="revanced_hide_shorts_tagged_products_summary_on">Tagged products are hidden</string>
|
||||||
<string name="revanced_hide_shorts_tagged_products_summary_off">Tagged products are shown</string>
|
<string name="revanced_hide_shorts_tagged_products_summary_off">Tagged products are shown</string>
|
||||||
|
@ -621,7 +624,7 @@
|
||||||
<string name="revanced_hide_shorts_channel_bar_title">Hide channel bar</string>
|
<string name="revanced_hide_shorts_channel_bar_title">Hide channel bar</string>
|
||||||
<string name="revanced_hide_shorts_channel_bar_summary_on">Channel bar is hidden</string>
|
<string name="revanced_hide_shorts_channel_bar_summary_on">Channel bar is hidden</string>
|
||||||
<string name="revanced_hide_shorts_channel_bar_summary_off">Channel bar is shown</string>
|
<string name="revanced_hide_shorts_channel_bar_summary_off">Channel bar is shown</string>
|
||||||
<string name="revanced_hide_shorts_video_title_title">Hide Shorts video title</string>
|
<string name="revanced_hide_shorts_video_title_title">Hide video title</string>
|
||||||
<string name="revanced_hide_shorts_video_title_summary_on">Title is hidden</string>
|
<string name="revanced_hide_shorts_video_title_summary_on">Title is hidden</string>
|
||||||
<string name="revanced_hide_shorts_video_title_summary_off">Title is shown</string>
|
<string name="revanced_hide_shorts_video_title_summary_off">Title is shown</string>
|
||||||
<string name="revanced_hide_shorts_sound_metadata_label_title">Hide sound metadata label</string>
|
<string name="revanced_hide_shorts_sound_metadata_label_title">Hide sound metadata label</string>
|
||||||
|
@ -861,7 +864,7 @@
|
||||||
<string name="revanced_sb_new_segment_confirm_title">Are the times correct?</string>
|
<string name="revanced_sb_new_segment_confirm_title">Are the times correct?</string>
|
||||||
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
|
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
|
||||||
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
|
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
|
||||||
<string name="revanced_sb_new_segment_confirm_content">The segment lasts from %1$02d:%2$02d to %3$02d:%4$02d (%5$d minutes %6$02d seconds)\nIs it ready to submit?</string>
|
<string name="revanced_sb_new_segment_confirm_content">The segment is from\n\n%1$s\nto\n%2$s\n\n(%3$s)\n\nReady to submit?</string>
|
||||||
<string name="revanced_sb_new_segment_start_is_before_end">Start must be before the end</string>
|
<string name="revanced_sb_new_segment_start_is_before_end">Start must be before the end</string>
|
||||||
<string name="revanced_sb_new_segment_mark_locations_first">Mark two locations on the time bar first</string>
|
<string name="revanced_sb_new_segment_mark_locations_first">Mark two locations on the time bar first</string>
|
||||||
<string name="revanced_sb_new_segment_preview_segment_first">Preview the segment, and ensure it skips smoothly</string>
|
<string name="revanced_sb_new_segment_preview_segment_first">Preview the segment, and ensure it skips smoothly</string>
|
||||||
|
@ -904,7 +907,7 @@
|
||||||
<string name="revanced_spoof_app_version_summary_on">Version spoofed</string>
|
<string name="revanced_spoof_app_version_summary_on">Version spoofed</string>
|
||||||
<string name="revanced_spoof_app_version_summary_off">Version not spoofed</string>
|
<string name="revanced_spoof_app_version_summary_off">Version not spoofed</string>
|
||||||
<string name="revanced_spoof_app_version_user_dialog_message">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.</string>
|
<string name="revanced_spoof_app_version_user_dialog_message">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.</string>
|
||||||
<!-- It is ideal, but not required, if the text here appears alphabetically after the text used for 'revanced_spoof_app_version_title'.
|
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
|
||||||
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
|
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
|
||||||
<string name="revanced_spoof_app_version_target_title">Spoof app version target</string>
|
<string name="revanced_spoof_app_version_target_title">Spoof app version target</string>
|
||||||
<!-- 'RYD' is 'Return YouTube Dislike' -->
|
<!-- 'RYD' is 'Return YouTube Dislike' -->
|
||||||
|
@ -1082,6 +1085,21 @@
|
||||||
<string name="revanced_slide_to_seek_summary_on">Slide to seek is enabled</string>
|
<string name="revanced_slide_to_seek_summary_on">Slide to seek is enabled</string>
|
||||||
<string name="revanced_slide_to_seek_summary_off">Slide to seek is not enabled</string>
|
<string name="revanced_slide_to_seek_summary_off">Slide to seek is not enabled</string>
|
||||||
</patch>
|
</patch>
|
||||||
|
<patch id="misc.fix.playback.SpoofClientPatch">
|
||||||
|
<string name="revanced_spoof_client_screen_title">Spoof client</string>
|
||||||
|
<string name="revanced_spoof_client_screen_summary">Spoof the client to prevent playback issues</string>
|
||||||
|
<string name="revanced_spoof_client_title">Spoof client</string>
|
||||||
|
<string name="revanced_spoof_client_summary_on">Client is spoofed</string>
|
||||||
|
<string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
|
||||||
|
<string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
|
||||||
|
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_client_spoof_title' -->
|
||||||
|
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
|
||||||
|
<string name="revanced_spoof_client_use_ios_summary">Spoof the client to iOS instead of an Android Testsuite</string>
|
||||||
|
<string name="revanced_spoof_client_use_ios_summary_on">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</string>
|
||||||
|
<string name="revanced_spoof_client_use_ios_summary_off">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</string>
|
||||||
|
<string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
|
||||||
|
<string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
|
||||||
|
</patch>
|
||||||
<!-- This patch is no longer used, these strings are not in use, and these strings will be deleted in the future. -->
|
<!-- This patch is no longer used, these strings are not in use, and these strings will be deleted in the future. -->
|
||||||
<patch id="misc.fix.playback.SpoofSignaturePatch">
|
<patch id="misc.fix.playback.SpoofSignaturePatch">
|
||||||
<string name="revanced_spoof_signature_verification_screen_title">Spoof app signature</string>
|
<string name="revanced_spoof_signature_verification_screen_title">Spoof app signature</string>
|
||||||
|
@ -1155,9 +1173,9 @@
|
||||||
<string name="revanced_other_category_title">Other settings</string>
|
<string name="revanced_other_category_title">Other settings</string>
|
||||||
<string name="revanced_client_ads_category_title">Client-side ads</string>
|
<string name="revanced_client_ads_category_title">Client-side ads</string>
|
||||||
<string name="revanced_surestream_ads_category_title">Server-side surestream ads</string>
|
<string name="revanced_surestream_ads_category_title">Server-side surestream ads</string>
|
||||||
<string name="revanced_debug_title">Debug logging</string>
|
<string name="revanced_twitch_debug_title">Debug logging</string>
|
||||||
<string name="revanced_debug_summary_on">Debug logs are enabled</string>
|
<string name="revanced_twitch_debug_summary_on">Debug logs are enabled</string>
|
||||||
<string name="revanced_debug_summary_off">Debug logs are disabled</string>
|
<string name="revanced_twitch_debug_summary_off">Debug logs are disabled</string>
|
||||||
</patch>
|
</patch>
|
||||||
</app>
|
</app>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue