mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 18:03:55 +01:00
Compare commits
141 Commits
v1.0.0-dev
...
v1.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71a08ca5eb | ||
|
|
4ba5b324a6 | ||
|
|
05ee34c756 | ||
|
|
73adc6f98c | ||
|
|
eb97257c41 | ||
|
|
9d99df6f31 | ||
|
|
62c6543485 | ||
|
|
39cf505d84 | ||
|
|
f55ad46322 | ||
|
|
a91432f6ca | ||
|
|
15cf96aac7 | ||
|
|
813529944b | ||
|
|
eef7d863cb | ||
|
|
255f00dd63 | ||
|
|
f4e289c8df | ||
|
|
017bcfa04d | ||
|
|
da81df06ff | ||
|
|
38c06e2d6f | ||
|
|
e9fe8d4d12 | ||
|
|
bb356cb71c | ||
|
|
45c75cfb0e | ||
|
|
08aad61b61 | ||
|
|
dd1981a086 | ||
|
|
abf42a89c5 | ||
|
|
7dfcf3b730 | ||
|
|
dd0d58fc3b | ||
|
|
15630fe9f9 | ||
|
|
27f6aa5b7b | ||
|
|
a2038a0507 | ||
|
|
1748cd98a4 | ||
|
|
0c3b512fe3 | ||
|
|
113637183a | ||
|
|
595e0ed37e | ||
|
|
6655f4b5e5 | ||
|
|
8798780d22 | ||
|
|
edbd40563f | ||
|
|
96e7aed843 | ||
|
|
96f76b2eb5 | ||
|
|
f25c8d2cd1 | ||
|
|
fa3f6e2f33 | ||
|
|
c2aa3b8365 | ||
|
|
e09f25cb75 | ||
|
|
0207d08c17 | ||
|
|
ae1127c02d | ||
|
|
e49fb3c969 | ||
|
|
80462bbe1c | ||
|
|
cc5634851a | ||
|
|
8043396ee4 | ||
|
|
70bfd792bf | ||
|
|
e6f3b3cd21 | ||
|
|
364155f683 | ||
|
|
24245b8d53 | ||
|
|
51aeebe1e8 | ||
|
|
6f72b84a32 | ||
|
|
2ea7ccdf43 | ||
|
|
2aa5c2d611 | ||
|
|
1d1a20f7aa | ||
|
|
34f6dcfc63 | ||
|
|
a182ff5bdb | ||
|
|
32d828fc67 | ||
|
|
927e12791b | ||
|
|
8242fde8f1 | ||
|
|
923b0d9a01 | ||
|
|
98ce25d50f | ||
|
|
5cf23a72d2 | ||
|
|
7193575eee | ||
|
|
51a061fe2d | ||
|
|
c6dae56521 | ||
|
|
08b4294f5e | ||
|
|
5114ae1a2a | ||
|
|
385c278e05 | ||
|
|
2fbefea52c | ||
|
|
529fa1edff | ||
|
|
291441c5d7 | ||
|
|
a08c4429d0 | ||
|
|
426597889f | ||
|
|
a80fc38b60 | ||
|
|
d6d6438110 | ||
|
|
e757e13987 | ||
|
|
acdb44477c | ||
|
|
1a3fed3b65 | ||
|
|
5877714361 | ||
|
|
57f506dbfd | ||
|
|
c2e0e918d0 | ||
|
|
8b5d316ad3 | ||
|
|
2d1c3ee109 | ||
|
|
89d5b08d85 | ||
|
|
024ecb2fb0 | ||
|
|
54196e70ab | ||
|
|
b67dec3294 | ||
|
|
22d8791ac6 | ||
|
|
34449abe41 | ||
|
|
42253f016a | ||
|
|
89dcb56a9f | ||
|
|
0c16b51e93 | ||
|
|
d29329fb32 | ||
|
|
9cb59b44e3 | ||
|
|
9987679f66 | ||
|
|
38d77be08b | ||
|
|
f65199c028 | ||
|
|
a63db11046 | ||
|
|
78d1c97aa1 | ||
|
|
affd51d2c1 | ||
|
|
067d530901 | ||
|
|
c46c150629 | ||
|
|
5cb333d769 | ||
|
|
c3f5eec804 | ||
|
|
38761e8e26 | ||
|
|
a55fa685f6 | ||
|
|
c36c5f80b4 | ||
|
|
9fa44443fa | ||
|
|
858468dc1d | ||
|
|
dcc825088c | ||
|
|
f073388b9a | ||
|
|
97e1b65900 | ||
|
|
046d1f05f7 | ||
|
|
51c45c636f | ||
|
|
2f2a0ff5e3 | ||
|
|
0a57a1d1c1 | ||
|
|
dc59fe1b22 | ||
|
|
73a47dc3f6 | ||
|
|
d474d669e6 | ||
|
|
ecacfd72e8 | ||
|
|
fb4dc1dcfc | ||
|
|
af4d514038 | ||
|
|
cc558b35e9 | ||
|
|
ab234789cc | ||
|
|
61554ce809 | ||
|
|
65c6794a7c | ||
|
|
051e80cc2b | ||
|
|
f4d25aeea2 | ||
|
|
95be597eab | ||
|
|
9e49e71364 | ||
|
|
d01658c840 | ||
|
|
ba1103aca3 | ||
|
|
85236c57b8 | ||
|
|
bf2b2ae791 | ||
|
|
9e1dac57e7 | ||
|
|
790c84a00e | ||
|
|
d32424bc42 | ||
|
|
084fc60d3f |
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -1,5 +1,6 @@
|
||||
name: Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -20,7 +21,7 @@ jobs:
|
||||
- name: Setup JDK
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
- name: Setup Node.js
|
||||
@@ -32,7 +33,7 @@ jobs:
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew build
|
||||
run: ./gradlew build clean
|
||||
- name: Setup semantic-release
|
||||
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
||||
- name: Release
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -111,4 +111,7 @@ gradle-app.setting
|
||||
.gradletasknamecache
|
||||
|
||||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
|
||||
# Potentially copyrighted test APK
|
||||
*.apk
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -4,5 +4,5 @@
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
11
.releaserc
11
.releaserc
@@ -20,6 +20,15 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"@semantic-release/github"
|
||||
[
|
||||
"@semantic-release/github",
|
||||
{
|
||||
"assets": [
|
||||
{
|
||||
"path": "build/libs/*.jar"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
179
CHANGELOG.md
179
CHANGELOG.md
@@ -1,3 +1,182 @@
|
||||
# [1.0.0-dev.14](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.13...v1.0.0-dev.14) (2022-06-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* spelling mistake ([52f9147](https://github.com/revanced/revanced-patches/commit/52f9147ee8d591f786397d174dc02a141d9250a9))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `Dependencies` annotation ([85806bb](https://github.com/revanced/revanced-patches/commit/85806bb355e342ecb33d4ee1e76f9edf89b2c2ee))
|
||||
* `GeneralBytecodeAds` and `GeneralResourceAds` patch ([f99bbef](https://github.com/revanced/revanced-patches/commit/f99bbef4c911ac2492166c7a3792ea11ffceffab))
|
||||
|
||||
# [1.0.0-dev.13](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.12...v1.0.0-dev.13) (2022-05-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* migrate patches to latest patcher api changes ([8a0ee03](https://github.com/revanced/revanced-patches/commit/8a0ee03a71cf4a000c9a7246d0e64ed8291a5127))
|
||||
* missing extension method `doRecursively` ([e9c9460](https://github.com/revanced/revanced-patches/commit/e9c946008ee912652d288e515b83b52ae2d239d8))
|
||||
|
||||
# [1.0.0-dev.12](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.11...v1.0.0-dev.12) (2022-05-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* wrong annotation and signature in patches ([a0fdee8](https://github.com/revanced/revanced-patches/commit/a0fdee81a6d6773603520e7c3040ae8637642d58))
|
||||
|
||||
# [1.0.0-dev.11](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* breaking changes by `revanced-patcher` dependency ([7e485b4](https://github.com/revanced/revanced-patches/commit/7e485b4ffe204d724809aeb9bd9f693a35ded94d))
|
||||
* breaking patcher changes ([50f9cc5](https://github.com/revanced/revanced-patches/commit/50f9cc52acfd5bc23330ecd23d8d85678a9d3eee))
|
||||
* breaking patcher changes ([cbb9e2c](https://github.com/revanced/revanced-patches/commit/cbb9e2cd1fa829e1d1dd92dbd40131b11ae6a05b))
|
||||
* bugfixes in `microg` ([a43b33b](https://github.com/revanced/revanced-patches/commit/a43b33bdbb2b36e0a8f991fa11dfeeec34de01f9))
|
||||
* write while reading resources and remove checking for "." in resource extensions ([7bc6094](https://github.com/revanced/revanced-patches/commit/7bc60943cb2350e89dac091ec9c98c5effd0b8a9))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* begin `MicroG Patch` ([91474ba](https://github.com/revanced/revanced-patches/commit/91474ba07376c13e7a71685dfd8b6e6913ed5ee9))
|
||||
* update MicroG patch to latest version ([c24f806](https://github.com/revanced/revanced-patches/commit/c24f8063a04f89aea2d2f7087a435738de7dfeae))
|
||||
|
||||
# [1.0.0-dev.11](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* breaking changes by `revanced-patcher` dependency ([7e485b4](https://github.com/revanced/revanced-patches/commit/7e485b4ffe204d724809aeb9bd9f693a35ded94d))
|
||||
* breaking patcher changes ([50f9cc5](https://github.com/revanced/revanced-patches/commit/50f9cc52acfd5bc23330ecd23d8d85678a9d3eee))
|
||||
* breaking patcher changes ([cbb9e2c](https://github.com/revanced/revanced-patches/commit/cbb9e2cd1fa829e1d1dd92dbd40131b11ae6a05b))
|
||||
* bugfixes in `microg` ([a43b33b](https://github.com/revanced/revanced-patches/commit/a43b33bdbb2b36e0a8f991fa11dfeeec34de01f9))
|
||||
* write while reading resources and remove checking for "." in resource extensions ([7bc6094](https://github.com/revanced/revanced-patches/commit/7bc60943cb2350e89dac091ec9c98c5effd0b8a9))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* begin `MicroG Patch` ([91474ba](https://github.com/revanced/revanced-patches/commit/91474ba07376c13e7a71685dfd8b6e6913ed5ee9))
|
||||
* update MicroG patch to latest version ([c24f806](https://github.com/revanced/revanced-patches/commit/c24f8063a04f89aea2d2f7087a435738de7dfeae))
|
||||
|
||||
# [1.0.0-dev.10](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `create-button-signature` ([a173f6e](https://github.com/revanced/revanced-patches/commit/a173f6e5a7e65943657e2072e8a72a4a680e5277))
|
||||
* breaking changes by `revanced-patcher` dependency ([e12e484](https://github.com/revanced/revanced-patches/commit/e12e484e3796c5c9c8505b677838cdf8432f2e79))
|
||||
* loop in `amoled` patch ([c4c86b6](https://github.com/revanced/revanced-patches/commit/c4c86b65fd8b2463c1d86ad2e46ec9f08e60d47c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add `amoled` patch ([d61bac4](https://github.com/revanced/revanced-patches/commit/d61bac4f8243d0ef72ca91c7c1d5facd858d515e))
|
||||
* update patches to latest version ([bad25de](https://github.com/revanced/revanced-patches/commit/bad25dec1d73137f8b7a1bf4daaceb2279b4d48c))
|
||||
|
||||
# [1.0.0-dev.9](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.8...v1.0.0-dev.9) (2022-05-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clean after building ([a2df3fb](https://github.com/revanced/revanced-patches/commit/a2df3fbc9761b07f3010542fa8684ade00e4dc91))
|
||||
|
||||
# [1.0.0-dev.8](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.7...v1.0.0-dev.8) (2022-05-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* publish releases ([83916f9](https://github.com/revanced/revanced-patches/commit/83916f96d27989dcbb35c0ba6ef326a16b470501))
|
||||
|
||||
# [1.0.0-dev.7](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.6...v1.0.0-dev.7) (2022-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use the latest version of patcher dependency ([fe4a439](https://github.com/revanced/revanced-patches/commit/fe4a439cb2bc5e385ae13e8e155f25bb15e74633))
|
||||
|
||||
# [1.0.0-dev.6](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.5...v1.0.0-dev.6) (2022-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update patches ([91b8ec8](https://github.com/revanced/revanced-patches/commit/91b8ec81f33417798546c32db708fe09ada3930c))
|
||||
|
||||
# [1.0.0-dev.5](https://github.com/revanced/revanced-patches/compare/v1.0.0-dev.4...v1.0.0-dev.5) (2022-05-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* `enable-seekbar-tapping` patch ([52fd726](https://github.com/revanced/revanced-patches/commit/52fd726d9b0d2efbd0f9742fc84ad01ccdcff168))
|
||||
* `Index` in wrong package ([2f9360f](https://github.com/revanced/revanced-patches/commit/2f9360f57cc8415564534fbbd8bd5e2a83a1b629))
|
||||
* `minimized-playback` & `old-quality-layout` wrong opcodes ([b45d175](https://github.com/revanced/revanced-patches/commit/b45d175c6f1ece6da894ab16128c2644d262c9c7))
|
||||
* `minimized-playback` patch ([55677a4](https://github.com/revanced/revanced-patches/commit/55677a44ff965c0b92c3f1d771bd68c12c142ad4))
|
||||
* `SignatureChecker` not handling nullable field `methodMetadata` ([17bcf78](https://github.com/revanced/revanced-patches/commit/17bcf786a85ccf1f7d9f5a66a044a3c26def09bb))
|
||||
* accidentally removed code in refactor ([0077e26](https://github.com/revanced/revanced-patches/commit/0077e26d23cc112b671a41614a55348fac2c88ca))
|
||||
* add missing `trimIndent()` to string literals ([76d3c71](https://github.com/revanced/revanced-patches/commit/76d3c71b67edebd79f2cdb1bb28e4d2969d72223))
|
||||
* add missing opcode for `create-button-method` ([0a398ef](https://github.com/revanced/revanced-patches/commit/0a398ef364f91a0dd9608df1a036a2515476ccf2))
|
||||
* attempt on all patches ([3395d69](https://github.com/revanced/revanced-patches/commit/3395d69747103a4bdf314297aa0bfa6ef6a0fc36))
|
||||
* breaking changes of the patcher ([1a49bbd](https://github.com/revanced/revanced-patches/commit/1a49bbdbc4ff6f427934259536218e161908b449))
|
||||
* breaking patcher changes ([581d1b0](https://github.com/revanced/revanced-patches/commit/581d1b0ca7d15adcdb1ab6116ef035acfe701757))
|
||||
* disable `hide-suggestions-patch` patch until fixed ([99099ea](https://github.com/revanced/revanced-patches/commit/99099ea0bc12f5f25896967db642442df69d0c4f))
|
||||
* incorrect endIndex (fixed in Patcher) ([424788e](https://github.com/revanced/revanced-patches/commit/424788edd777110cdaff97500556d18628f33385))
|
||||
* modified opcode for `show-video-ads-constructor` ([a0dcea3](https://github.com/revanced/revanced-patches/commit/a0dcea3a13f68cae449dfaf445b542e339c83ff0))
|
||||
* multiple bugs in patches ([e37201d](https://github.com/revanced/revanced-patches/commit/e37201d0ceef474696857a0d8845950c888194d0))
|
||||
* name for `IntegrationsPatch` ([e46ef02](https://github.com/revanced/revanced-patches/commit/e46ef02302825d62b57912b2747a25f858036bb7))
|
||||
* print instruction index of warning ([9e29aee](https://github.com/revanced/revanced-patches/commit/9e29aeeeff222412f6c45cf7e4879f8ec53ca6ee))
|
||||
* remove `HideSuggestionsPatch` from `Index` ([f32e474](https://github.com/revanced/revanced-patches/commit/f32e4747b512c675b807ff5eebfd0b8e66173fba))
|
||||
* signature checker with changes of patcher ([e82459d](https://github.com/revanced/revanced-patches/commit/e82459d37759e1a5a860d3e7fcdf69d95b06858e))
|
||||
* tests failing ([102793f](https://github.com/revanced/revanced-patches/commit/102793f24f8bf7c7fd254968b29d65da7b2b962f))
|
||||
* update `HomeAdsPatch` ([62f1801](https://github.com/revanced/revanced-patches/commit/62f1801e9cbee53c0be3413c245161bd941e4aec))
|
||||
* version in package metadata of music ([b299205](https://github.com/revanced/revanced-patches/commit/b299205aa7cde82f1f55fc598de3ff8d80b8bcb0))
|
||||
* **VideoAds:** remove `istore1` opcode ([dc4ec57](https://github.com/revanced/revanced-patches/commit/dc4ec574414c5df959efa0ca8f1cd39a812fedf8))
|
||||
* wrong access flag in signature for `Create button patch` ([9fbb89d](https://github.com/revanced/revanced-patches/commit/9fbb89d05336a256a0759eea6095e073946c45e5))
|
||||
* wrong opcode for `create-button-method` ([3214650](https://github.com/revanced/revanced-patches/commit/32146506f139aebc44cd5faffb7706b8b9c21c3d))
|
||||
* wrong opcode pattern for `create-button-method` ([f4d8a85](https://github.com/revanced/revanced-patches/commit/f4d8a8525bc64b90748b21979d463977a21dcd85))
|
||||
* wrong opcode pattern for `enable-seekbar-tapping-signature` ([1d83395](https://github.com/revanced/revanced-patches/commit/1d833957ed3e01188770c85e3d84e483419bd797))
|
||||
* wrong opcode pattern for signature in `Hide suggestions patch` ([535aee0](https://github.com/revanced/revanced-patches/commit/535aee08408b990c80f5966c13fa84666a8b35d0))
|
||||
* wrong patches in `upgrade-tab-remover` ([5182290](https://github.com/revanced/revanced-patches/commit/518229031ceca049ad790f7b77b19405d39f0ce1))
|
||||
* wrong signature for `hide-reels-signature` ([2d9ff2a](https://github.com/revanced/revanced-patches/commit/2d9ff2af0a991d7721f3741187716a3b08bb4029))
|
||||
* wrong signatures for patch `Old Quality Layout Patch` ([823e503](https://github.com/revanced/revanced-patches/commit/823e503d84037bdf27b09f17e63383f963c76854))
|
||||
* wrong versions of patches ([a112b22](https://github.com/revanced/revanced-patches/commit/a112b22ce6e685204caab6f95f511e26ef95806b))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `hide-shorts-button` patch ([88352ee](https://github.com/revanced/revanced-patches/commit/88352ee6ecd23faa4a7fd9f7495e67fa1d3e33bd))
|
||||
* `tastebuilder-remover` for music ([a6aeca3](https://github.com/revanced/revanced-patches/commit/a6aeca31bd80b8c4a8acd071e22faca6e136bdb0))
|
||||
* Add (WIP) Signature Checker ([ae4c7b2](https://github.com/revanced/revanced-patches/commit/ae4c7b29f211c461de460f97f3a8656e795adafb))
|
||||
* add home ads patch ([36cddd1](https://github.com/revanced/revanced-patches/commit/36cddd1488683e19e2b927e34c80a4f0f3cace35))
|
||||
* added `codecs-unlock` patch ([e5fd7ce](https://github.com/revanced/revanced-patches/commit/e5fd7cece94b1ff5342178f59b29576db806e0f6))
|
||||
* display metadata for each signature in `SignatureChecker` ([736a71f](https://github.com/revanced/revanced-patches/commit/736a71fac21a32dbb1eef9c3a9f0d3005e7d9ca0))
|
||||
* get required register dynamically ([0924ca2](https://github.com/revanced/revanced-patches/commit/0924ca2ad30ae865dcc0fd484cb0da517e827352))
|
||||
* integrations patch ([19c0b0d](https://github.com/revanced/revanced-patches/commit/19c0b0d194bb97c7248ea7a9b081176961653b9d))
|
||||
* migrate to dalvik patches ([e088c67](https://github.com/revanced/revanced-patches/commit/e088c671081bcf75586ccc1c4bdbed9366e93874))
|
||||
* Patches for YouTube Music ([b60c9d3](https://github.com/revanced/revanced-patches/commit/b60c9d33b611bb4d5b55bb419652bc14b0309792))
|
||||
* remove obsolete patch `Hide suggestions patch` ([e65c6f2](https://github.com/revanced/revanced-patches/commit/e65c6f240ed23a54271d20a90fc57ec65cafc02d))
|
||||
|
||||
# [1.0.0-dev.4](https://github.com/ReVancedTeam/revanced-patches/compare/v1.0.0-dev.3...v1.0.0-dev.4) (2022-03-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* use supplier instead of KClass ([08af6e5](https://github.com/ReVancedTeam/revanced-patches/commit/08af6e54af79ef9ef4fb3372a348ce9b6fba4d20))
|
||||
* use supplier instead of KClass ([91aa019](https://github.com/ReVancedTeam/revanced-patches/commit/91aa019f8d3d87fbf7affeb7abc2b02ba87af5c3))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* signature of patches was changed
|
||||
* signature of patches was changed
|
||||
|
||||
# [1.0.0-dev.3](https://github.com/ReVancedTeam/revanced-patches/compare/v1.0.0-dev.2...v1.0.0-dev.3) (2022-03-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* OldQualityLayout, HideSuggestions, HideReels, EnableSeekbarTapping ([04a7cff](https://github.com/ReVancedTeam/revanced-patches/commit/04a7cfff20d2734b1c92713de4e7e08a3b93ee85))
|
||||
|
||||
# [1.0.0-dev.2](https://github.com/ReVancedTeam/revanced-patches/compare/v1.0.0-dev.1...v1.0.0-dev.2) (2022-03-21)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
kotlin("jvm") version "1.6.10"
|
||||
kotlin("jvm") version "1.6.21"
|
||||
java
|
||||
`maven-publish`
|
||||
}
|
||||
@@ -8,8 +8,9 @@ group = "app.revanced"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven {
|
||||
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher") // note the "r"!
|
||||
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") // note the "r"!
|
||||
credentials {
|
||||
// DO NOT set these variables in the project's gradle.properties.
|
||||
// Instead, you should set them in:
|
||||
@@ -22,14 +23,10 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.21")
|
||||
|
||||
implementation("org.ow2.asm:asm:9.2")
|
||||
implementation("org.ow2.asm:asm-util:9.2")
|
||||
implementation("org.ow2.asm:asm-tree:9.2")
|
||||
implementation("org.ow2.asm:asm-commons:9.2")
|
||||
|
||||
implementation("app.revanced:revanced-patcher:1.+") // use latest version.
|
||||
implementation("app.revanced:revanced-patcher:1.0.0-dev.18")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.21")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -37,15 +34,21 @@ java {
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
val isGitHubCI = System.getenv("GITHUB_ACTOR") != null
|
||||
|
||||
publishing {
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patches") // note the "s"!
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
if (isGitHubCI) {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/revanced/revanced-patches") // note the "s"!
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
publications {
|
||||
@@ -53,4 +56,4 @@ publishing {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
kotlin.code.style = official
|
||||
version = 1.0.0-dev.2
|
||||
version = 1.0.0-dev.14
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
36
src/main/kotlin/app/revanced/extensions/Extensions.kt
Normal file
36
src/main/kotlin/app/revanced/extensions/Extensions.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package app.revanced.extensions
|
||||
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||
import org.w3c.dom.Node
|
||||
|
||||
internal fun MutableMethodImplementation.injectHideCall(
|
||||
index: Int,
|
||||
register: Int
|
||||
) {
|
||||
this.addInstruction(
|
||||
index,
|
||||
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->HideView(Landroid/view/View;)V".toInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
internal fun Node.doRecursively(action: (Node) -> Unit) {
|
||||
action(this)
|
||||
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
||||
}
|
||||
|
||||
internal fun String.startsWithAny(vararg prefix: String): Boolean {
|
||||
for (_prefix in prefix)
|
||||
if (this.startsWith(_prefix))
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
internal fun String.containsAny(vararg others: String): Boolean {
|
||||
for (other in others)
|
||||
if (this.contains(other))
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package app.revanced.patches
|
||||
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patches.ads.VideoAds
|
||||
import app.revanced.patches.layouts.CreateButtonRemover
|
||||
import app.revanced.patches.layouts.MinimizedPlayback
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Index contains all the patches and should be imported when using this library.
|
||||
*/
|
||||
@Suppress("Unused")
|
||||
object Index {
|
||||
/**
|
||||
* Array of patches.
|
||||
* New patches should be added to the array.
|
||||
*/
|
||||
val patches: Array<KClass<out Patch>> = arrayOf(
|
||||
VideoAds::class,
|
||||
MinimizedPlayback::class,
|
||||
CreateButtonRemover::class
|
||||
)
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package app.revanced.patches.ads
|
||||
|
||||
import app.revanced.patcher.cache.Cache
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.signature.Signature
|
||||
import app.revanced.patcher.writer.ASMWriter.insertAt
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.objectweb.asm.tree.VarInsnNode
|
||||
|
||||
class VideoAds : Patch("VideoAds") {
|
||||
override fun execute(cache: Cache): PatchResult {
|
||||
val showVideoAdsMethodData = cache.methods["show-video-ads"].findParentMethod(
|
||||
Signature(
|
||||
"method",
|
||||
Type.VOID_TYPE,
|
||||
Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL,
|
||||
arrayOf(Type.BOOLEAN_TYPE),
|
||||
null
|
||||
)
|
||||
) ?: return PatchResultError("Could not find required method to patch")
|
||||
|
||||
showVideoAdsMethodData.method.instructions.insertAt(
|
||||
0,
|
||||
VarInsnNode(Opcodes.ISTORE, 1),
|
||||
MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
"fi/vanced/libraries/youtube/whitelisting/Whitelist",
|
||||
"shouldShowAds",
|
||||
Type.getMethodDescriptor(Type.BOOLEAN_TYPE)
|
||||
)
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package app.revanced.patches.layouts
|
||||
|
||||
import app.revanced.patcher.cache.Cache
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.writer.ASMWriter.insertAt
|
||||
import org.objectweb.asm.Opcodes
|
||||
import org.objectweb.asm.tree.MethodInsnNode
|
||||
import org.objectweb.asm.tree.VarInsnNode
|
||||
|
||||
class CreateButtonRemover : Patch("create-button-remover") {
|
||||
override fun execute(cache: Cache): PatchResult {
|
||||
val patchData = cache.methods["create-button-patch"]
|
||||
|
||||
patchData.method.instructions.insertAt(
|
||||
patchData.scanData.endIndex - 1,
|
||||
VarInsnNode(
|
||||
Opcodes.ALOAD,
|
||||
6
|
||||
),
|
||||
MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
"fi/razerman/youtube/XAdRemover",
|
||||
"hideCreateButton",
|
||||
"(Landroid/view/View;)V"
|
||||
)
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.layouts
|
||||
|
||||
import app.revanced.patcher.cache.Cache
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
|
||||
class MinimizedPlayback : Patch("minimized-playback") {
|
||||
override fun execute(cache: Cache): PatchResult {
|
||||
cache.methods["minimized-playback-manager"].method.instructions.clear()
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.music.audio.codecs.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class CodecsUnlockCompatibility
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package app.revanced.patches.music.audio.codecs.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.data.implementation.toMethodWalker
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
||||
import app.revanced.patches.music.audio.codecs.signatures.AllCodecsReferenceSignature
|
||||
import app.revanced.patches.music.audio.codecs.signatures.CodecsLockSignature
|
||||
|
||||
@Patch
|
||||
@Name("codecs-unlock")
|
||||
@Description("Enables more audio codecs. Usually results in better audio quality but may depend on song and device.")
|
||||
@CodecsUnlockCompatibility
|
||||
@Version("0.0.1")
|
||||
class CodecsUnlockPatch : BytecodePatch(
|
||||
listOf(
|
||||
CodecsLockSignature, AllCodecsReferenceSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
var result = signatures.first().result!!
|
||||
|
||||
val implementation = result.method.implementation!!
|
||||
|
||||
val instructionIndex = result.scanResult.startIndex
|
||||
|
||||
result = signatures.last().result!!
|
||||
val codecMethod =
|
||||
data.toMethodWalker(result.immutableMethod).nextMethod(result.scanResult.startIndex).getMethod()
|
||||
|
||||
implementation.replaceInstruction(
|
||||
instructionIndex,
|
||||
"invoke-static {}, ${codecMethod.definingClass}->${codecMethod.name}()Ljava/util/Set;".toInstruction()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package app.revanced.patches.music.audio.codecs.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("all-codecs-reference-signature")
|
||||
@MatchingMethod(
|
||||
"Laari;",
|
||||
"b",
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@CodecsUnlockCompatibility
|
||||
@Version("0.0.1")
|
||||
object AllCodecsReferenceSignature : MethodSignature(
|
||||
"J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.GOTO,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.GOTO,
|
||||
Opcode.MOVE_EXCEPTION,
|
||||
Opcode.INVOKE_SUPER,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.RETURN_WIDE
|
||||
), listOf("itag")
|
||||
)
|
||||
@@ -0,0 +1,47 @@
|
||||
package app.revanced.patches.music.audio.codecs.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("codec-lock-signature")
|
||||
@MatchingMethod(
|
||||
"Labwj;",
|
||||
"a",
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@CodecsUnlockCompatibility
|
||||
@Version("0.0.1")
|
||||
object CodecsLockSignature : MethodSignature(
|
||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.RETURN_OBJECT
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.music.audio.exclusiveaudio.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class ExclusiveAudioCompatibility
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package app.revanced.patches.music.audio.exclusiveaudio.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
||||
import app.revanced.patches.music.audio.exclusiveaudio.signatures.ExclusiveAudioSignature
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Patch
|
||||
@Name("exclusive-audio-playback")
|
||||
@Description("Add the option to play music without video.")
|
||||
@ExclusiveAudioCompatibility
|
||||
@Version("0.0.1")
|
||||
class ExclusiveAudioPatch : BytecodePatch(
|
||||
listOf(
|
||||
ExclusiveAudioSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result = signatures.first().result!!.findParentMethod(@Name("audio-only-enabler-method") @MatchingMethod(
|
||||
"Lgmd;",
|
||||
"d"
|
||||
) @DirectPatternScanMethod @ExclusiveAudioCompatibility @Version(
|
||||
"0.0.1"
|
||||
) object : MethodSignature(
|
||||
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.GOTO,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.RETURN
|
||||
)
|
||||
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
||||
|
||||
val implementation = result.method.implementation!!
|
||||
implementation.replaceInstruction(
|
||||
implementation.instructions.count() - 1, "const/4 v0, 0x1".toInstruction()
|
||||
)
|
||||
implementation.addInstruction(
|
||||
"return v0".toInstruction()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package app.revanced.patches.music.audio.exclusiveaudio.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("exclusive-audio-signature")
|
||||
@MatchingMethod(
|
||||
"Lgmd;", "c"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@ExclusiveAudioCompatibility
|
||||
@Version("0.0.1")
|
||||
object ExclusiveAudioSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("L", "Z"),
|
||||
listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.CONST_4,
|
||||
Opcode.GOTO,
|
||||
Opcode.NOP,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.GOTO,
|
||||
Opcode.RETURN_VOID
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.music.layout.tastebuilder.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class RemoveTasteBuilderCompatibility
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package app.revanced.patches.music.layout.tastebuilder.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
|
||||
import app.revanced.patches.music.layout.tastebuilder.signatures.TasteBuilderConstructorSignature
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||
|
||||
@Patch
|
||||
@Name("tasteBuilder-remover")
|
||||
@Description("Removes the \"Tell us which artists you like\" card from the Home screen. The same functionality can be triggered from the settings anyway.")
|
||||
@RemoveTasteBuilderCompatibility
|
||||
@Version("0.0.1")
|
||||
class RemoveTasteBuilderPatch : BytecodePatch(
|
||||
listOf(
|
||||
TasteBuilderConstructorSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result = signatures.first().result!!
|
||||
val implementation = result.method.implementation!!
|
||||
|
||||
val insertIndex = result.scanResult.endIndex - 8
|
||||
|
||||
val register = (implementation.instructions[insertIndex] as Instruction22c).registerA
|
||||
|
||||
val instructionList = """
|
||||
const/16 v1, 0x8
|
||||
invoke-virtual {v${register}, v1}, Landroid/view/View;->setVisibility(I)V
|
||||
""".trimIndent().toInstructions().toMutableList()
|
||||
|
||||
implementation.addInstructions(
|
||||
insertIndex, instructionList
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package app.revanced.patches.music.layout.tastebuilder.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("taste-builder-constructor")
|
||||
@MatchingMethod(
|
||||
"Lkyu;", "<init>"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@RemoveTasteBuilderCompatibility
|
||||
@Version("0.0.1")
|
||||
object TasteBuilderConstructorSignature : MethodSignature(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.music.layout.upgradebutton.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class RemoveUpgradeButtonCompatibility
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package app.revanced.patches.music.layout.upgradebutton.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
|
||||
import app.revanced.patches.music.layout.upgradebutton.signatures.PivotBarConstructorSignature
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction22t
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
|
||||
@Patch
|
||||
@Name("upgrade-button-remover")
|
||||
@Description("Remove the upgrade tab from t he pivot bar in YouTube music.")
|
||||
@RemoveUpgradeButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
class RemoveUpgradeButtonPatch : BytecodePatch(
|
||||
listOf(
|
||||
PivotBarConstructorSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result = signatures.first().result!!
|
||||
val implementation = result.method.implementation!!
|
||||
|
||||
val pivotBarElementFieldRef =
|
||||
(implementation.instructions[result.scanResult.endIndex - 1] as Instruction22c).reference
|
||||
|
||||
val register = (implementation.instructions.first() as Instruction35c).registerC
|
||||
// first compile all the needed instructions
|
||||
val instructionList = """
|
||||
invoke-interface { v0 }, Ljava/util/List;->size()I
|
||||
move-result v1
|
||||
const/4 v2, 0x3
|
||||
invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
|
||||
iput-object v0, v$register, $pivotBarElementFieldRef
|
||||
""".trimIndent().toInstructions().toMutableList()
|
||||
|
||||
|
||||
// replace the instruction to retain the label at given index
|
||||
implementation.replaceInstruction(
|
||||
result.scanResult.endIndex - 1, instructionList[0] // invoke-interface
|
||||
)
|
||||
// do not forget to remove this instruction since we added it already
|
||||
instructionList.removeFirst()
|
||||
|
||||
val exitInstruction = instructionList.last() // iput-object
|
||||
implementation.addInstruction(
|
||||
result.scanResult.endIndex, exitInstruction
|
||||
)
|
||||
// do not forget to remove this instruction since we added it already
|
||||
instructionList.removeLast()
|
||||
|
||||
// add the necessary if statement to remove the upgrade tab button in case it exists
|
||||
instructionList.add(
|
||||
2, // if-le
|
||||
BuilderInstruction22t(
|
||||
Opcode.IF_LE, 1, 2, implementation.newLabelForIndex(result.scanResult.endIndex)
|
||||
)
|
||||
)
|
||||
|
||||
implementation.addInstructions(
|
||||
result.scanResult.endIndex, instructionList
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package app.revanced.patches.music.layout.upgradebutton.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("pivot-bar-constructor")
|
||||
@MatchingMethod(
|
||||
"Lhfu;", "<init2>"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@RemoveUpgradeButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
object PivotBarConstructorSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
listOf("L", "Z"),
|
||||
listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.GOTO,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.GOTO,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.GOTO,
|
||||
Opcode.NOP,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.RETURN_VOID
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.music.premium.backgroundplay.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class BackgroundPlayCompatibility
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.music.premium.backgroundplay.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
|
||||
import app.revanced.patches.music.premium.backgroundplay.signatures.BackgroundPlaybackDisableSignature
|
||||
|
||||
@Patch
|
||||
@Name("background-play")
|
||||
@Description("Enable playing music in the background.")
|
||||
@BackgroundPlayCompatibility
|
||||
@Version("0.0.1")
|
||||
class BackgroundPlayPatch : BytecodePatch(
|
||||
listOf(
|
||||
BackgroundPlaybackDisableSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
signatures.first().result!!.method.implementation!!.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package app.revanced.patches.music.premium.backgroundplay.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("background-playback-disabler-signature")
|
||||
@MatchingMethod(
|
||||
"Lafgf;", "e"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@BackgroundPlayCompatibility
|
||||
@Version("0.0.1")
|
||||
object BackgroundPlaybackDisableSignature : MethodSignature(
|
||||
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET,
|
||||
Opcode.AND_INT_LIT16,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.GOTO,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.CONST_4,
|
||||
Opcode.RETURN,
|
||||
Opcode.RETURN,
|
||||
Opcode.RETURN
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.ad.general.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.19.36", "17.20.37")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class GeneralAdsCompatibility
|
||||
|
||||
@@ -0,0 +1,491 @@
|
||||
package app.revanced.patches.youtube.ad.general.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.injectHideCall
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.data.implementation.proxy
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.extensions.softCompareTo
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||
import app.revanced.patches.youtube.ad.general.resource.patch.GeneralResourceAdsPatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.BuilderInstruction
|
||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||
import org.jf.dexlib2.builder.instruction.*
|
||||
import org.jf.dexlib2.iface.Method
|
||||
import org.jf.dexlib2.iface.MethodImplementation
|
||||
import org.jf.dexlib2.iface.instruction.Instruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
import org.jf.dexlib2.iface.reference.MethodReference
|
||||
import org.jf.dexlib2.iface.reference.Reference
|
||||
import org.jf.dexlib2.iface.reference.StringReference
|
||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||
import org.jf.dexlib2.immutable.ImmutableMethodParameter
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
||||
|
||||
@Patch
|
||||
@Dependencies(
|
||||
dependencies = [ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class, GeneralResourceAdsPatch::class]
|
||||
)
|
||||
@Name("general-bytecode-ads")
|
||||
@Description("Patch to remove general ads in bytecode.")
|
||||
@GeneralAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralBytecodeAdsPatch : BytecodePatch(
|
||||
listOf()
|
||||
) {
|
||||
// a constant used by litho
|
||||
private val lithoConstant = 0xaed2868
|
||||
|
||||
// list of resource names to get the id of
|
||||
private val resourceIds = arrayOf(
|
||||
"ad_attribution",
|
||||
"reel_multiple_items_shelf",
|
||||
"info_cards_drawer_header",
|
||||
"endscreen_element_layout_video",
|
||||
"endscreen_element_layout_circle",
|
||||
"endscreen_element_layout_icon",
|
||||
"promoted_video_item_land",
|
||||
"promoted_video_item_full_bleed",
|
||||
).map {
|
||||
ResourceIdMappingProviderResourcePatch.resourceMappings[it]!!
|
||||
}
|
||||
|
||||
private val stringReferences = arrayOf(
|
||||
"Claiming to use more elements than provided",
|
||||
"loadVideo() called on LocalDirector in wrong state",
|
||||
"LoggingProperties are not in proto format"
|
||||
)
|
||||
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
// iterating through all classes is expensive
|
||||
for (classDef in data.classes) {
|
||||
var mutableClass: MutableClass? = null
|
||||
|
||||
method@ for (method in classDef.methods) {
|
||||
var mutableMethod: MutableMethod? = null
|
||||
|
||||
if (method.implementation == null) continue@method
|
||||
|
||||
val instructions = method.implementation!!.instructions
|
||||
instructions.forEachIndexed { index, instruction ->
|
||||
when (instruction.opcode) {
|
||||
Opcode.CONST -> {
|
||||
// TODO: find a way to de-duplicate code.
|
||||
// The issue is we need to save mutableClass and mutableMethod to the existing fields
|
||||
when ((instruction as Instruction31i).wideLiteral) {
|
||||
resourceIds[0] -> { // general ads
|
||||
// and is followed by an instruction with the mnemonic INVOKE_VIRTUAL
|
||||
val insertIndex = index + 1
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
||||
|
||||
// create proxied method, make sure to not re-resolve() the current class
|
||||
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||
if (mutableMethod == null) mutableMethod =
|
||||
mutableClass!!.findMutableMethodOf(method)
|
||||
|
||||
// insert hide call to hide the view corresponding to the resource
|
||||
val viewRegister = (invokeInstruction as Instruction35c).registerC
|
||||
mutableMethod!!.implementation!!.injectHideCall(insertIndex, viewRegister)
|
||||
|
||||
}
|
||||
|
||||
resourceIds[1] -> { // reel ads
|
||||
// and is followed by an instruction at insertIndex with the mnemonic IPUT_OBJECT
|
||||
val insertIndex = index + 4
|
||||
val iPutInstruction = instructions.elementAt(insertIndex)
|
||||
if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
|
||||
|
||||
// create proxied method, make sure to not re-resolve() the current class
|
||||
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||
if (mutableMethod == null) mutableMethod =
|
||||
mutableClass!!.findMutableMethodOf(method)
|
||||
|
||||
val viewRegister = (iPutInstruction as Instruction22c).registerA
|
||||
mutableMethod!!.implementation!!.injectHideCall(insertIndex, viewRegister)
|
||||
}
|
||||
|
||||
resourceIds[2] -> { // info cards ads
|
||||
// and is followed by an instruction with the mnemonic INVOKE_VIRTUAL
|
||||
val removeIndex = index - 1
|
||||
val invokeInstruction = instructions.elementAt(removeIndex)
|
||||
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
||||
|
||||
// create proxied method, make sure to not re-resolve() the current class
|
||||
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||
if (mutableMethod == null) mutableMethod =
|
||||
mutableClass!!.findMutableMethodOf(method)
|
||||
|
||||
mutableMethod!!.implementation!!.removeInstruction(removeIndex)
|
||||
}
|
||||
|
||||
resourceIds[3], resourceIds[4], resourceIds[5] -> { // end screen ads
|
||||
// and is followed by an instruction with the mnemonic IPUT_OBJECT
|
||||
val insertIndex = index + 7
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
|
||||
|
||||
// create proxied method, make sure to not re-resolve() the current class
|
||||
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||
if (mutableMethod == null) mutableMethod =
|
||||
mutableClass!!.findMutableMethodOf(method)
|
||||
|
||||
// TODO: dynamically get registers
|
||||
mutableMethod!!.implementation!!.addInstructions(
|
||||
insertIndex, """
|
||||
const/16 v1, 0x8
|
||||
invoke-virtual {v0,v1}, Landroid/widget/FrameLayout;->setVisibility(I)V
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
}
|
||||
|
||||
resourceIds[6] -> {
|
||||
// and is followed by an instruction with the mnemonic INVOKE_DIRECT
|
||||
val insertIndex = index + 3
|
||||
val invokeInstruction = instructions.elementAt(insertIndex)
|
||||
if (invokeInstruction.opcode != Opcode.INVOKE_DIRECT) return@forEachIndexed
|
||||
|
||||
// create proxied method, make sure to not re-resolve() the current class
|
||||
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||
if (mutableMethod == null) mutableMethod =
|
||||
mutableClass!!.findMutableMethodOf(method)
|
||||
|
||||
// insert hide call to hide the view corresponding to the resource
|
||||
val viewRegister = (invokeInstruction as Instruction35c).registerE
|
||||
mutableMethod!!.implementation!!.injectHideCall(insertIndex, viewRegister)
|
||||
}
|
||||
|
||||
resourceIds[7] -> {
|
||||
// TODO, go to class, hide the inflated view
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Opcode.CONST_STRING -> {
|
||||
|
||||
when (((instruction as Instruction21c).reference as StringReference).string) {
|
||||
stringReferences[0] -> {
|
||||
val stringInstruction = instructions.elementAt(3)
|
||||
if (stringInstruction.opcode == Opcode.CONST_STRING) return@forEachIndexed
|
||||
|
||||
// create proxied method, make sure to not re-resolve() the current class
|
||||
if (mutableClass == null) mutableClass = data.proxy(classDef).resolve()
|
||||
if (mutableMethod == null) mutableMethod =
|
||||
mutableClass!!.findMutableMethodOf(method)
|
||||
|
||||
// return the method
|
||||
val insertIndex = 1 // after super constructor
|
||||
mutableMethod!!.implementation!!.addInstruction(
|
||||
insertIndex, BuilderInstruction10x(Opcode.RETURN_VOID)
|
||||
)
|
||||
}
|
||||
|
||||
stringReferences[1] -> {
|
||||
// TODO: migrate video ads patch to here if necessary
|
||||
}
|
||||
|
||||
stringReferences[2] -> { // Litho ads
|
||||
// create proxied method.
|
||||
val proxy = data.proxy(classDef)
|
||||
val mutableClass = proxy.resolve()
|
||||
|
||||
// add getIsEmpty method
|
||||
mutableClass.addGetIsEmptyMethod()
|
||||
|
||||
// get required method to patch and get references from
|
||||
val lithoMethod = getLithoMethod(mutableClass)
|
||||
?: return PatchResultError("Could not find required litho method to patch.")
|
||||
val lithoMethodImplementation = lithoMethod.implementation!!
|
||||
|
||||
// create and add getTemplateName method
|
||||
val getTemplateMethod =
|
||||
mutableClass.createGetTemplateNameMethod(lithoMethodImplementation)
|
||||
mutableClass.addMethod(getTemplateMethod)
|
||||
|
||||
val lithoInstructions = lithoMethodImplementation.instructions
|
||||
val thisType = mutableClass.type
|
||||
val templateNameParameterType = getTemplateMethod.parameterTypes.first()
|
||||
|
||||
// get reference descriptors
|
||||
val indexOfReference1 = lithoInstructions.indexOfFirst {
|
||||
it.opcode == Opcode.INVOKE_STATIC_RANGE
|
||||
}
|
||||
val descriptor1 =
|
||||
lithoInstructions.elementAt(indexOfReference1).toDescriptor<MethodReference>()
|
||||
val descriptor2 = lithoInstructions.elementAt(indexOfReference1 + 2)
|
||||
.toDescriptor<FieldReference>()
|
||||
|
||||
// create label
|
||||
val lithoRemoveLabel = lithoMethodImplementation.newLabelForIndex(0)
|
||||
|
||||
// create branch instructions
|
||||
val ifEqzFirstInstruction =
|
||||
BuilderInstruction21t(Opcode.IF_EQZ, 0, lithoRemoveLabel)
|
||||
val ifEqzSecondInstruction =
|
||||
BuilderInstruction21t(Opcode.IF_EQZ, 1, lithoRemoveLabel)
|
||||
|
||||
// create blocks
|
||||
val parameters = lithoMethod.parameterTypes.joinToString("") { it }
|
||||
val registers = lithoMethodImplementation.registerCount
|
||||
val block1 = """
|
||||
invoke-static/range {p3}, $thisType->getTemplateName($templateNameParameterType)Ljava/lang/String;
|
||||
move-result-object v0
|
||||
""".trimIndent().toInstructions(parameters, registers, false)
|
||||
val block2 = """
|
||||
move-object/from16 v1, p3
|
||||
iget-object v2, v1, $templateNameParameterType->b:Ljava/nio/ByteBuffer;
|
||||
invoke-static {v0, v2}, Lfi/razerman/youtube/litho/LithoAdRemoval;->containsAd(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z
|
||||
move-result v1
|
||||
""".trimIndent().toInstructions(parameters, registers, false)
|
||||
val block3 = """
|
||||
move-object/from16 v2, p1
|
||||
invoke-static {v2}, $descriptor1
|
||||
move-result-object v0
|
||||
iget-object v0, v0, $descriptor2
|
||||
return-object v0
|
||||
""".trimIndent().toInstructions(parameters, registers, false)
|
||||
|
||||
// insert blocks and branch instructions
|
||||
lithoMethodImplementation.insertBlocks(
|
||||
0,
|
||||
block1,
|
||||
listOf(ifEqzFirstInstruction),
|
||||
block2,
|
||||
listOf(ifEqzSecondInstruction),
|
||||
block3,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private fun getLithoMethod(mutableClass: MutableClass) = mutableClass.methods.firstOrNull {
|
||||
it.implementation?.instructions?.any { instruction ->
|
||||
instruction.opcode == Opcode.CONST && (instruction as Instruction31i).narrowLiteral == lithoConstant
|
||||
} ?: false
|
||||
}
|
||||
|
||||
private fun MutableClass.addGetIsEmptyMethod() {
|
||||
val getIsEmptyImplementation = MutableMethodImplementation(1)
|
||||
|
||||
// create target instructions
|
||||
val firstTargetInstruction = BuilderInstruction11n(Opcode.CONST_4, 0, 1)
|
||||
val secondTargetInstruction = BuilderInstruction11n(Opcode.CONST_4, 0, 0)
|
||||
|
||||
// add instructions to the instruction list
|
||||
getIsEmptyImplementation.addInstructions(
|
||||
0, listOf(
|
||||
// BuilderInstruction21t(Opcode.IF_EQZ, 0, first),
|
||||
BuilderInstruction35c(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
ImmutableMethodReference("Ljava/lang/String;", "isEmpty", null, "Z")
|
||||
),
|
||||
BuilderInstruction11x(Opcode.MOVE_RESULT, 0),
|
||||
// BuilderInstruction21t(Opcode.IF_EQZ, 0, second),
|
||||
// BuilderInstruction10t(Opcode.GOTO, first),
|
||||
secondTargetInstruction,
|
||||
BuilderInstruction11x(Opcode.RETURN, 0),
|
||||
firstTargetInstruction,
|
||||
BuilderInstruction11x(Opcode.RETURN, 0),
|
||||
)
|
||||
)
|
||||
|
||||
val getIsEmptyInstructions = getIsEmptyImplementation.instructions
|
||||
|
||||
// create labels for the target instructions
|
||||
val firstLabel =
|
||||
getIsEmptyImplementation.newLabelForIndex(getIsEmptyInstructions.indexOf(firstTargetInstruction))
|
||||
val secondLabel =
|
||||
getIsEmptyImplementation.newLabelForIndex(getIsEmptyInstructions.indexOf(secondTargetInstruction))
|
||||
|
||||
// create branch instructions to the labels
|
||||
val ifEqzFirstInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 0, firstLabel)
|
||||
val ifEqzSecondInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 0, secondLabel)
|
||||
val gotoInstruction = BuilderInstruction10t(Opcode.GOTO, firstLabel)
|
||||
|
||||
// insert remaining branch instructions, order of adding those instructions is important
|
||||
getIsEmptyImplementation.addInstructions(
|
||||
2, listOf(
|
||||
ifEqzSecondInstruction, gotoInstruction
|
||||
)
|
||||
)
|
||||
getIsEmptyImplementation.addInstruction(
|
||||
0, ifEqzFirstInstruction
|
||||
)
|
||||
|
||||
this.addMethod(
|
||||
createMutableMethod(
|
||||
this.type, "getIsEmpty", "Z", "Ljava/lang/String;", getIsEmptyImplementation
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableClass.createGetTemplateNameMethod(lithoMethodImplementation: MethodImplementation): MutableMethod {
|
||||
var counter = 1
|
||||
val descriptors = buildList {
|
||||
for (instruction in lithoMethodImplementation.instructions) {
|
||||
if (instruction !is ReferenceInstruction) continue
|
||||
if (counter++ > 4) break
|
||||
|
||||
add(instruction.toDescriptor<MethodReference>())
|
||||
}
|
||||
}
|
||||
|
||||
val getTemplateNameImplementation = MutableMethodImplementation(2)
|
||||
|
||||
// create code blocks
|
||||
val block1 = """
|
||||
invoke-virtual {p0}, ${descriptors[0]}
|
||||
move-result-object p0
|
||||
const v0, $lithoConstant
|
||||
invoke-static {p0, v0}, ${descriptors[1]}
|
||||
move-result-object p0
|
||||
""".trimIndent().toInstructions()
|
||||
val block2 = """
|
||||
invoke-static {p0}, ${descriptors[2]}
|
||||
move-result-object p0
|
||||
invoke-virtual {p0}, ${descriptors[3]}
|
||||
move-result-object v0
|
||||
invoke-static {v0}, ${this.type}->getIsEmpty(Ljava/lang/String;)Z
|
||||
move-result v0
|
||||
""".trimIndent().toInstructions()
|
||||
val block3 = """
|
||||
invoke-virtual {p0}, ${descriptors[3]}
|
||||
move-result-object p0
|
||||
return-object p0
|
||||
""".trimIndent().toInstructions()
|
||||
|
||||
// create target instruction
|
||||
val targetInstruction = BuilderInstruction11n(Opcode.CONST_4, 1, 0)
|
||||
// and remaining instruction
|
||||
val returnInstruction = BuilderInstruction11x(Opcode.RETURN_OBJECT, 1)
|
||||
|
||||
// insert blocks and instructions
|
||||
getTemplateNameImplementation.insertBlocks(
|
||||
0,
|
||||
block1,
|
||||
block2,
|
||||
block3,
|
||||
listOf(
|
||||
targetInstruction, returnInstruction
|
||||
),
|
||||
)
|
||||
|
||||
// create label for target instruction
|
||||
val targetInstructionLabel =
|
||||
getTemplateNameImplementation.newLabelForIndex(getTemplateNameImplementation.instructions.size - 2)
|
||||
|
||||
// create branch instructions to the label
|
||||
val ifEqzInstruction = BuilderInstruction21t(Opcode.IF_EQZ, 1, targetInstructionLabel)
|
||||
val ifNezInstruction = BuilderInstruction21t(Opcode.IF_NEZ, 0, targetInstructionLabel)
|
||||
|
||||
// insert branch instructions
|
||||
getTemplateNameImplementation.addInstruction(
|
||||
block1.size, ifEqzInstruction
|
||||
)
|
||||
getTemplateNameImplementation.addInstruction(
|
||||
block1.size + block2.size + 1, ifNezInstruction
|
||||
)
|
||||
|
||||
// create the method
|
||||
return createMutableMethod(
|
||||
this.type,
|
||||
"getTemplateName",
|
||||
"Ljava/lang/String;",
|
||||
descriptors[0].split("->")[0], // a bit weird to get the type this way,
|
||||
getTemplateNameImplementation
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableMethodImplementation.insertBlocks(
|
||||
startIndex: Int,
|
||||
vararg blocks: List<BuilderInstruction>,
|
||||
) {
|
||||
blocks.reversed().forEach {
|
||||
this.addInstructions(
|
||||
startIndex, it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableClass.addMethod(mutableMethod: MutableMethod) {
|
||||
this.methods.add(mutableMethod)
|
||||
}
|
||||
|
||||
private fun createMutableMethod(
|
||||
definingClass: String, name: String, returnType: String, parameter: String, implementation: MethodImplementation
|
||||
) = ImmutableMethod(
|
||||
definingClass, name, listOf(
|
||||
ImmutableMethodParameter(
|
||||
parameter, null, null
|
||||
)
|
||||
), returnType, AccessFlags.PRIVATE or AccessFlags.STATIC, null, null, implementation
|
||||
).toMutable()
|
||||
|
||||
private fun MutableClass.findMutableMethodOf(
|
||||
method: Method
|
||||
) = this.methods.first {
|
||||
it.softCompareTo(
|
||||
ImmutableMethodReference(
|
||||
method.definingClass, method.name, method.parameters, method.returnType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private inline fun <reified T : Reference> Instruction.toDescriptor(): String {
|
||||
val reference = (this as ReferenceInstruction).reference
|
||||
return when (T::class) {
|
||||
MethodReference::class -> {
|
||||
val methodReference = reference as MethodReference
|
||||
"${methodReference.definingClass}->${methodReference.name}(${
|
||||
methodReference.parameterTypes.joinToString(
|
||||
""
|
||||
) { it }
|
||||
})${methodReference.returnType}"
|
||||
}
|
||||
|
||||
FieldReference::class -> {
|
||||
val fieldReference = reference as FieldReference
|
||||
"${fieldReference.definingClass}->${fieldReference.name}:${fieldReference.type}"
|
||||
}
|
||||
|
||||
else -> throw PatchResultError("Unsupported reference type")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package app.revanced.patches.youtube.ad.general.resource.patch
|
||||
|
||||
import app.revanced.extensions.doRecursively
|
||||
import app.revanced.extensions.startsWithAny
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.ResourceData
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Dependencies(dependencies = [FixLocaleConfigErrorPatch::class])
|
||||
@Name("general-resource-ads")
|
||||
@Description("Patch to remove general ads in resources.")
|
||||
@GeneralAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
class GeneralResourceAdsPatch : ResourcePatch() {
|
||||
// list of resource file names which need to be hidden
|
||||
private val resourceFileNames = arrayOf(
|
||||
"compact_promoted_video_item.xml",
|
||||
"inline_muted_metadata_swap.xml",
|
||||
"interstitial_promo_view.xml",
|
||||
"pip_ad_overlay.xml",
|
||||
"promoted_",
|
||||
"watch_metadata_companion_cards.xml",
|
||||
//"watch_while_activity.xml" // FIXME: find out why patching this resource fails
|
||||
)
|
||||
|
||||
// the attributes to change the value of
|
||||
private val replacements = arrayOf(
|
||||
"height",
|
||||
"width",
|
||||
"marginTop",
|
||||
)
|
||||
|
||||
override fun execute(data: ResourceData): PatchResult {
|
||||
data.forEach {
|
||||
if (!it.name.startsWithAny(*resourceFileNames)) return@forEach
|
||||
|
||||
// for each file in the "layouts" directory replace all necessary attributes content
|
||||
data.getXmlEditor(it.absolutePath).use { editor ->
|
||||
editor.file.doRecursively { node ->
|
||||
replacements.forEach replacement@{ replacement ->
|
||||
if (node !is Element) return@replacement
|
||||
|
||||
node.getAttributeNode("android:layout_$replacement")?.let { attribute ->
|
||||
attribute.textContent = "1.0dip"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.ad.home.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.03.38", "17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class PromotionsCompatibility
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
package app.revanced.patches.youtube.ad.home.patch
|
||||
|
||||
import app.revanced.extensions.injectHideCall
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.data.implementation.toMethodWalker
|
||||
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.ad.home.annotation.PromotionsCompatibility
|
||||
import app.revanced.patches.youtube.ad.home.signatures.PromotedDiscoveryActionParentSignature
|
||||
import app.revanced.patches.youtube.ad.home.signatures.PromotedDiscoveryAppParentSignature
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
||||
|
||||
//@Patch(dependencies = [IntegrationsPatch::class])
|
||||
@Name("home-promo-ads")
|
||||
@Description("Patch to remove promoted ads in YouTube.")
|
||||
@PromotionsCompatibility
|
||||
@Version("0.0.1")
|
||||
class PromotionsPatch : BytecodePatch(
|
||||
listOf(
|
||||
PromotedDiscoveryAppParentSignature, PromotedDiscoveryActionParentSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
for (signature in signatures) {
|
||||
val result = signature.result!!
|
||||
|
||||
val requiredMethod =
|
||||
result.findParentMethod(@Name("promotion-ads-signature") @MatchingMethod(name = "d") @DirectPatternScanMethod @PromotionsCompatibility @Version(
|
||||
"0.0.1"
|
||||
) object : MethodSignature(
|
||||
"V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("Z", "Z"), null
|
||||
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
||||
|
||||
val toBePatchedInvokeOffset =
|
||||
requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT }
|
||||
val toBePatchedMethod =
|
||||
data.toMethodWalker(requiredMethod.immutableMethod).nextMethod(toBePatchedInvokeOffset, true)
|
||||
.getMethod() as MutableMethod
|
||||
|
||||
val implementation = toBePatchedMethod.implementation!!
|
||||
val invokeVirtualOffset = implementation.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_VIRTUAL }
|
||||
|
||||
val moveResultInstruction = implementation.instructions[invokeVirtualOffset + 1]
|
||||
if (moveResultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return PatchResultError("The toBePatchedInvokeOffset offset was wrong in ${this.javaClass.patchName}")
|
||||
|
||||
val register = (moveResultInstruction as Instruction11x).registerA
|
||||
implementation.injectHideCall(invokeVirtualOffset + 2, register)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package app.revanced.patches.youtube.ad.home.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.ad.home.annotation.PromotionsCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("promoted-discovery-app-parent-signature")
|
||||
@MatchingMethod(
|
||||
"Ljqb;", "lG"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@PromotionsCompatibility
|
||||
@Version("0.0.1")
|
||||
object PromotedDiscoveryActionParentSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC,
|
||||
listOf("L", "L"),
|
||||
listOf(
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL_RANGE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.CONST_4,
|
||||
Opcode.XOR_INT_2ADDR,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,61 @@
|
||||
package app.revanced.patches.youtube.ad.home.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.ad.home.annotation.PromotionsCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("promoted-discovery-action-parent-signature")
|
||||
@MatchingMethod(
|
||||
"Ljqj;",
|
||||
"lG"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@PromotionsCompatibility
|
||||
@Version("0.0.1")
|
||||
|
||||
object PromotedDiscoveryAppParentSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC,
|
||||
listOf("L", "L"),
|
||||
listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.NEW_ARRAY,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_GE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.APUT_OBJECT,
|
||||
Opcode.ADD_INT_LIT8,
|
||||
Opcode.GOTO
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.ad.video.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class VideoAdsCompatibility
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package app.revanced.patches.youtube.ad.video.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
|
||||
import app.revanced.patches.youtube.ad.video.signatures.ShowVideoAdsConstructorSignature
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
@Patch
|
||||
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||
@Name("video-ads")
|
||||
@Description("Patch to remove ads in the YouTube video player.")
|
||||
@VideoAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
class VideoAdsPatch : BytecodePatch(
|
||||
listOf(
|
||||
ShowVideoAdsConstructorSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result =
|
||||
signatures.first().result!!.findParentMethod(@Name("show-video-ads-method-signature") @MatchingMethod(
|
||||
definingClass = "zai"
|
||||
) @DirectPatternScanMethod @VideoAdsCompatibility @Version("0.0.1") object : MethodSignature(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), null
|
||||
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
||||
|
||||
// Override the parameter by calling shouldShowAds and setting the parameter to the result
|
||||
result.method.implementation!!.addInstructions(
|
||||
0, """
|
||||
invoke-static { }, Lfi/vanced/libraries/youtube/whitelisting/Whitelist;->shouldShowAds()Z
|
||||
move-result v1
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package app.revanced.patches.youtube.ad.video.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("show-video-ads-constructor-signature")
|
||||
@MatchingMethod(
|
||||
"Laair",
|
||||
"<init>",
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@VideoAdsCompatibility
|
||||
@Version("0.0.1")
|
||||
object ShowVideoAdsConstructorSignature : MethodSignature(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
null, // either CONST_4 or CONST_16
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.RETURN_VOID
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.interaction.seekbar.annotation
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class SeekbarTappingCompatibility
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package app.revanced.patches.youtube.interaction.seekbar.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
|
||||
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingParentSignature
|
||||
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingSignature
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
||||
import org.jf.dexlib2.iface.Method
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11n
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
@Patch
|
||||
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||
@Name("seekbar-tapping")
|
||||
@Description("Enable tapping on the seekbar of the YouTube player.")
|
||||
@SeekbarTappingCompatibility
|
||||
@Version("0.0.1")
|
||||
class EnableSeekbarTappingPatch : BytecodePatch(
|
||||
listOf(
|
||||
SeekbarTappingParentSignature, SeekbarTappingSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
var result = signatures.first().result!!
|
||||
|
||||
val tapSeekMethods = mutableMapOf<String, Method>()
|
||||
|
||||
// find the methods which tap the seekbar
|
||||
for (it in result.definingClassProxy.immutableClass.methods) {
|
||||
if (it.implementation == null) continue
|
||||
|
||||
val instructions = it.implementation!!.instructions
|
||||
// here we make sure we actually find the method because it has more then 7 instructions
|
||||
if (instructions.count() < 7) continue
|
||||
|
||||
// we know that the 7th instruction has the opcode CONST_4
|
||||
val instruction = instructions.elementAt(6)
|
||||
if (instruction.opcode != Opcode.CONST_4) continue
|
||||
|
||||
// the literal for this instruction has to be either 1 or 2
|
||||
val literal = (instruction as Instruction11n).narrowLiteral
|
||||
|
||||
// method founds
|
||||
if (literal == 1) tapSeekMethods["P"] = it
|
||||
if (literal == 2) tapSeekMethods["O"] = it
|
||||
}
|
||||
|
||||
// replace map because we dont need the upper one anymore
|
||||
result = signatures.last().result!!
|
||||
|
||||
val implementation = result.method.implementation!!
|
||||
|
||||
// if tap-seeking is enabled, do not invoke the two methods below
|
||||
val pMethod = tapSeekMethods["P"]!!
|
||||
val oMethod = tapSeekMethods["O"]!!
|
||||
|
||||
// get the required register
|
||||
val instruction = implementation.instructions[result.scanResult.endIndex]
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return PatchResultError("Could not find the correct register")
|
||||
val register = (instruction as Instruction35c).registerC
|
||||
|
||||
// the instructions are written in reverse order.
|
||||
implementation.addInstructions(
|
||||
result.scanResult.endIndex + 1, """
|
||||
invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V
|
||||
invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
|
||||
// if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label
|
||||
val elseLabel = implementation.newLabelForIndex(result.scanResult.endIndex + 1)
|
||||
implementation.addInstruction(
|
||||
result.scanResult.endIndex + 1, BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel)
|
||||
)
|
||||
implementation.addInstructions(
|
||||
result.scanResult.endIndex + 1, """
|
||||
invoke-static { }, Lfi/razerman/youtube/preferences/BooleanPreferences;->isTapSeekingEnabled()Z
|
||||
move-result v0
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package app.revanced.patches.youtube.interaction.seekbar.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("enable-seekbar-tapping-parent")
|
||||
@MatchingMethod("Lzmx;", "I")
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@SeekbarTappingCompatibility
|
||||
@Version("0.0.1")
|
||||
object SeekbarTappingParentSignature : MethodSignature(
|
||||
"L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.NEW_ARRAY,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.APUT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.APUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.RETURN_OBJECT
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
package app.revanced.patches.youtube.interaction.seekbar.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("enable-seekbar-tapping-signature")
|
||||
@MatchingMethod("Lfbl;", "onTouchEvent")
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@SeekbarTappingCompatibility
|
||||
@Version("0.0.1")
|
||||
object SeekbarTappingSignature : MethodSignature(
|
||||
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.IGET,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.DIV_INT_2ADDR,
|
||||
Opcode.ADD_INT,
|
||||
Opcode.SUB_INT_2ADDR,
|
||||
Opcode.INT_TO_FLOAT,
|
||||
Opcode.CMPG_FLOAT,
|
||||
Opcode.IF_GTZ,
|
||||
Opcode.INT_TO_FLOAT,
|
||||
Opcode.CMPG_FLOAT,
|
||||
Opcode.IF_GTZ,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.amoled.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class AmoledCompatibility
|
||||
@@ -0,0 +1,47 @@
|
||||
package app.revanced.patches.youtube.layout.amoled.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.ResourceData
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.layout.amoled.annotations.AmoledCompatibility
|
||||
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||
import org.w3c.dom.Element
|
||||
import java.io.File
|
||||
|
||||
@Patch
|
||||
@Dependencies(
|
||||
dependencies = [
|
||||
FixLocaleConfigErrorPatch::class
|
||||
]
|
||||
)
|
||||
@Name("amoled")
|
||||
@Description("Enables pure black theme.")
|
||||
@AmoledCompatibility
|
||||
@Version("0.0.1")
|
||||
class AmoledPatch : ResourcePatch() {
|
||||
override fun execute(data: ResourceData): PatchResult {
|
||||
data.getXmlEditor("res${File.separator}values${File.separator}colors.xml").use { editor ->
|
||||
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
|
||||
|
||||
for (i in 0 until resourcesNode.childNodes.length) {
|
||||
val node = resourcesNode.childNodes.item(i)
|
||||
if (node !is Element) continue
|
||||
|
||||
val element = resourcesNode.childNodes.item(i) as Element
|
||||
element.textContent = when (element.getAttribute("name")) {
|
||||
"yt_black1", "yt_black1_opacity95", "yt_black2", "yt_black3", "yt_black4", "yt_status_bar_background_dark" -> "@android:color/black"
|
||||
"yt_selected_nav_label_dark" -> "#ffdf0000"
|
||||
else -> continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.createbutton.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class CreateButtonCompatibility
|
||||
@@ -0,0 +1,48 @@
|
||||
package app.revanced.patches.youtube.layout.createbutton.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patches.youtube.layout.createbutton.annotations.CreateButtonCompatibility
|
||||
import app.revanced.patches.youtube.layout.createbutton.signatures.CreateButtonSignature
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
@Patch
|
||||
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||
@Name("disable-create-button")
|
||||
@Description("Disable the create button.")
|
||||
@CreateButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
class CreateButtonRemoverPatch : BytecodePatch(
|
||||
listOf(
|
||||
CreateButtonSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result = signatures.first().result!!
|
||||
|
||||
// Get the required register which holds the view object we need to pass to the method hideCreateButton
|
||||
val implementation = result.method.implementation!!
|
||||
val instruction = implementation.instructions[result.scanResult.endIndex + 1]
|
||||
if (instruction.opcode != Opcode.INVOKE_STATIC) return PatchResultError("Could not find the correct register")
|
||||
val register = (instruction as Instruction35c).registerC
|
||||
|
||||
// Hide the button view via proxy by passing it to the hideCreateButton method
|
||||
implementation.addInstruction(
|
||||
result.scanResult.endIndex + 1,
|
||||
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->hideCreateButton(Landroid/view/View;)V".toInstruction()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package app.revanced.patches.youtube.layout.createbutton.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.layout.createbutton.annotations.CreateButtonCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("create-button-signature")
|
||||
@MatchingMethod(
|
||||
"Lknw", "z"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@CreateButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
object CreateButtonSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("Z"),
|
||||
listOf(
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.INVOKE_DIRECT_RANGE,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.minimizedplayback.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class MinimizedPlaybackCompatibility
|
||||
@@ -0,0 +1,38 @@
|
||||
package app.revanced.patches.youtube.layout.minimizedplayback.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
||||
import app.revanced.patches.youtube.layout.minimizedplayback.signatures.MinimizedPlaybackManagerSignature
|
||||
|
||||
|
||||
@Patch
|
||||
@Name("minimized-playback")
|
||||
@Description("Enable minimized and background playback.")
|
||||
@MinimizedPlaybackCompatibility
|
||||
@Version("0.0.1")
|
||||
class MinimizedPlaybackPatch : BytecodePatch(
|
||||
listOf(
|
||||
MinimizedPlaybackManagerSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
// Instead of removing all instructions like Vanced,
|
||||
// we return the method at the beginning instead
|
||||
signatures.first().result!!.method.implementation!!.addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package app.revanced.patches.youtube.layout.minimizedplayback.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("minimized-playback-manager-signature")
|
||||
@MatchingMethod(
|
||||
"Lyuf", "n"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@MinimizedPlaybackCompatibility
|
||||
@Version("0.0.1")
|
||||
object MinimizedPlaybackManagerSignature : MethodSignature(
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
listOf("L"),
|
||||
listOf(
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET,
|
||||
Opcode.AND_INT_LIT16,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.GOTO,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_EQZ
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.oldqualitylayout.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class OldQualityLayoutCompatibility
|
||||
@@ -0,0 +1,69 @@
|
||||
package app.revanced.patches.youtube.layout.oldqualitylayout.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
|
||||
import app.revanced.patches.youtube.layout.oldqualitylayout.signatures.OldQualityParentSignature
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
||||
|
||||
@Patch
|
||||
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||
@Name("old-quality-layout")
|
||||
@Description("Enable the original quality flyout menu.")
|
||||
@OldQualityLayoutCompatibility
|
||||
@Version("0.0.1")
|
||||
class OldQualityLayoutPatch : BytecodePatch(
|
||||
listOf(
|
||||
OldQualityParentSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result = signatures.first().result!!.findParentMethod(@Name("old-quality-signature") @MatchingMethod(
|
||||
definingClass = "Libh"
|
||||
) @FuzzyPatternScanMethod(2) @OldQualityLayoutCompatibility @Version("0.0.1") object : MethodSignature(
|
||||
"L", AccessFlags.FINAL or AccessFlags.PRIVATE, listOf("Z"), listOf(
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.IGET_OBJECT,
|
||||
)
|
||||
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
||||
|
||||
val implementation = result.method.implementation!!
|
||||
|
||||
// if useOldStyleQualitySettings == true, jump over all instructions
|
||||
val jmpInstruction = BuilderInstruction21t(
|
||||
Opcode.IF_NEZ, 0, implementation.instructions[result.scanResult.endIndex].location.labels.first()
|
||||
)
|
||||
implementation.addInstruction(5, jmpInstruction)
|
||||
implementation.addInstructions(
|
||||
0, """
|
||||
invoke-static { }, Lfi/razerman/youtube/XGlobals;->useOldStyleQualitySettings()Z
|
||||
move-result v0
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package app.revanced.patches.youtube.layout.oldqualitylayout.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("old-quality-parent-method-signature")
|
||||
@MatchingMethod(
|
||||
"Libh", "<init>"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@OldQualityLayoutCompatibility
|
||||
@Version("0.0.1")
|
||||
object OldQualityParentSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
listOf("L", "L", "L", "L", "L", "L", "L"),
|
||||
listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_4,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.reels.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class HideReelsCompatibility
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.youtube.layout.reels.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility
|
||||
import app.revanced.patches.youtube.layout.reels.signatures.HideReelsSignature
|
||||
|
||||
//@Patch TODO: converted to litho
|
||||
@Name("hide-reels")
|
||||
@Description("Hide reels on the page.")
|
||||
@HideReelsCompatibility
|
||||
@Version("0.0.1")
|
||||
class HideReelsPatch : BytecodePatch(
|
||||
listOf(
|
||||
HideReelsSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result = signatures.first().result!!
|
||||
val implementation = result.method.implementation!!
|
||||
|
||||
// HideReel will hide the reel view before it is being used,
|
||||
// so we pass the view to the HideReel method
|
||||
implementation.addInstruction(
|
||||
result.scanResult.endIndex,
|
||||
"invoke-static { v2 }, Lfi/razerman/youtube/XAdRemover;->HideReel(Landroid/view/View;)V".toInstruction()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package app.revanced.patches.youtube.layout.reels.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
@Name("hide-reels-signature")
|
||||
@MatchingMethod(
|
||||
"Ljvy", "<init>"
|
||||
)
|
||||
@FuzzyPatternScanMethod(3) // FIXME: Test this threshold and find the best value.
|
||||
@HideReelsCompatibility
|
||||
@Version("0.0.1")
|
||||
object HideReelsSignature : MethodSignature(
|
||||
null, AccessFlags.PROTECTED or AccessFlags.FINAL, listOf("L", "L"), null,
|
||||
listOf("multiReelDismissalCallback", "reelItemRenderers", "reelDismissalInfo")
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.shorts.button.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class ShortsButtonCompatibility
|
||||
@@ -0,0 +1,56 @@
|
||||
package app.revanced.patches.youtube.layout.shorts.button.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.patch.annotations.Dependencies
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
|
||||
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonTabenumSignature
|
||||
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonsViewSignature
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
||||
|
||||
@Patch
|
||||
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||
@Name("shorts-button")
|
||||
@Description("Hide the shorts button.")
|
||||
@ShortsButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
class ShortsButtonRemoverPatch : BytecodePatch(
|
||||
listOf(
|
||||
PivotBarButtonTabenumSignature, PivotBarButtonsViewSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
val result1 = signatures.first().result!!
|
||||
val implementation1 = result1.method.implementation!!
|
||||
val moveEnumInstruction = implementation1.instructions[result1.scanResult.endIndex]
|
||||
val enumRegister = (moveEnumInstruction as Instruction11x).registerA
|
||||
|
||||
val result2 = signatures.last().result!!
|
||||
val implementation2 = result2.method.implementation!!
|
||||
val moveViewInstruction = implementation2.instructions[result2.scanResult.endIndex]
|
||||
val viewRegister = (moveViewInstruction as Instruction11x).registerA
|
||||
|
||||
// Save the tab enum in XGlobals to avoid smali/register workarounds
|
||||
implementation1.addInstruction(
|
||||
result1.scanResult.endIndex + 1,
|
||||
"sput-object v$enumRegister, Lfi/razerman/youtube/XGlobals;->lastPivotTab:Ljava/lang/Enum;".toInstruction()
|
||||
)
|
||||
|
||||
// Hide the button view via proxy by passing it to the hideShortsButton method
|
||||
// It only hides it if the last tab name is "TAB_SHORTS"
|
||||
implementation2.addInstruction(
|
||||
result2.scanResult.endIndex + 2,
|
||||
"invoke-static { v$viewRegister }, Lfi/razerman/youtube/XAdRemover;->hideShortsButton(Landroid/view/View;)V".toInstruction()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package app.revanced.patches.youtube.layout.shorts.button.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("pivotbar-buttons-tabenum-signature")
|
||||
@MatchingMethod(
|
||||
"Lknw", "z"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@ShortsButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
object PivotBarButtonTabenumSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("Z"),
|
||||
listOf(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_STATIC, // SomeEnum.fromValue(tabOrdinal)
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.layout.shorts.button.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("pivotbar-buttons-view-signature")
|
||||
@MatchingMethod(
|
||||
"Lknw", "z"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@ShortsButtonCompatibility
|
||||
@Version("0.0.1")
|
||||
object PivotBarButtonsViewSignature : MethodSignature(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("Z"),
|
||||
listOf(
|
||||
Opcode.NEW_INSTANCE, // new StateListDrawable()
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.NEW_ARRAY,
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_16,
|
||||
Opcode.APUT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.MOVE,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL_RANGE, // pivotBar.getView(drawable, tabName, z, i, map, akebVar, optional)
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.03.38", "17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class IntegrationsCompatibility
|
||||
@@ -0,0 +1,67 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility
|
||||
import app.revanced.patches.youtube.misc.integrations.signatures.InitSignature
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
||||
|
||||
@Name("integrations")
|
||||
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
|
||||
@IntegrationsCompatibility
|
||||
@Version("0.0.1")
|
||||
class IntegrationsPatch : BytecodePatch(
|
||||
listOf(
|
||||
InitSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
if (data.findClass("Lapp/revanced/integrations/Globals") == null)
|
||||
return PatchResultError("Integrations have not been merged yet. This patch can not succeed without the integrations.")
|
||||
|
||||
val result = signatures.first().result!!
|
||||
|
||||
val implementation = result.method.implementation!!
|
||||
val count = implementation.registerCount - 1
|
||||
|
||||
implementation.addInstructions(
|
||||
result.scanResult.endIndex + 1, """
|
||||
invoke-static {v$count}, Lpl/jakubweg/StringRef;->setContext(Landroid/content/Context;)V
|
||||
sput-object v$count, Lapp/revanced/integrations/Globals;->context:Landroid/content/Context;
|
||||
""".trimIndent().toInstructions()
|
||||
)
|
||||
|
||||
val classDef = result.definingClassProxy.resolve()
|
||||
classDef.methods.add(
|
||||
ImmutableMethod(
|
||||
classDef.type,
|
||||
"getAppContext",
|
||||
null,
|
||||
"Landroid/content/Context;",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
1, """
|
||||
invoke-static { }, Lapp/revanced/integrations/Globals;->getAppContext()Landroid/content/Context;
|
||||
move-result-object v0
|
||||
return-object v0
|
||||
""".trimIndent().toInstructions(), null, null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility
|
||||
|
||||
@Name("init-signature")
|
||||
@MatchingMethod(
|
||||
"Lacuu", "onCreate"
|
||||
)
|
||||
@IntegrationsCompatibility
|
||||
@Version("0.0.1")
|
||||
object InitSignature : MethodSignature(
|
||||
null, null, null, null,
|
||||
listOf("Application creation")
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.misc.manifest.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class FixLocaleConfigErrorCompatibility
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.youtube.misc.manifest.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.ResourceData
|
||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.misc.manifest.annotations.FixLocaleConfigErrorCompatibility
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Name("locale-config-fix")
|
||||
@Description("Fix an error when building the resources by patching the manifest file.")
|
||||
@FixLocaleConfigErrorCompatibility
|
||||
@Version("0.0.1")
|
||||
class FixLocaleConfigErrorPatch : ResourcePatch() {
|
||||
override fun execute(data: ResourceData): PatchResult {
|
||||
// create an xml editor instance
|
||||
data.getXmlEditor("AndroidManifest.xml").use {
|
||||
// edit the application nodes attribute...
|
||||
val applicationNode = it
|
||||
.file
|
||||
.getElementsByTagName("application")
|
||||
.item(0) as Element
|
||||
|
||||
|
||||
// by replacing the attributes name
|
||||
val attribute = "android:localeConfig"
|
||||
applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute))
|
||||
applicationNode.removeAttribute("android:localeConfig")
|
||||
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package app.revanced.patches.youtube.misc.mapping.patch
|
||||
|
||||
import app.revanced.extensions.doRecursively
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.ResourceData
|
||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Name("resource-id-mapping-provider-resource-patch-dependency")
|
||||
@Description("This patch acts as a provider/ dependency for resource mappings.")
|
||||
@Version("0.0.1")
|
||||
class ResourceIdMappingProviderResourcePatch : ResourcePatch() {
|
||||
companion object {
|
||||
internal lateinit var resourceMappings: Map<String, Long>
|
||||
private set
|
||||
}
|
||||
|
||||
override fun execute(data: ResourceData): PatchResult {
|
||||
data.getXmlEditor("res/values/public.xml").use { editor ->
|
||||
resourceMappings = buildMap {
|
||||
editor.file.documentElement.doRecursively { node ->
|
||||
if (node !is Element) return@doRecursively
|
||||
val nameAttribute = node.getAttribute("name")
|
||||
if (node.nodeName != "public" || nameAttribute.startsWith("APKTOOL")) return@doRecursively
|
||||
this[nameAttribute] = node.getAttribute("id").substring(2).toLong(16)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.misc.microg.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility(
|
||||
[Package(
|
||||
"com.google.android.youtube", arrayOf("17.14.35", "17.19.36")
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class MicroGPatchCompatibility
|
||||
@@ -0,0 +1,169 @@
|
||||
package app.revanced.patches.youtube.misc.microg.patch.bytecode
|
||||
|
||||
import app.revanced.extensions.containsAny
|
||||
import app.revanced.extensions.startsWithAny
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.BytecodeData
|
||||
import app.revanced.patcher.data.implementation.proxy
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||
import app.revanced.patches.youtube.misc.microg.patch.resource.enum.StringReplaceMode
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.microg.signatures.GooglePlayUtilitySignature
|
||||
import app.revanced.patches.youtube.misc.microg.signatures.IntegrityCheckSignature
|
||||
import app.revanced.patches.youtube.misc.microg.signatures.PrimeSignature
|
||||
import app.revanced.patches.youtube.misc.microg.signatures.ServiceCheckSignature
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||
import org.jf.dexlib2.iface.reference.StringReference
|
||||
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
||||
|
||||
// @Patch TODO: finish patch
|
||||
@Name("microg-bytecode-patch")
|
||||
@Description("Patch to allow YouTube ReVanced to run without root and under a different package name.")
|
||||
@MicroGPatchCompatibility
|
||||
@Version("0.0.1")
|
||||
class MicroGBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
IntegrityCheckSignature, ServiceCheckSignature, GooglePlayUtilitySignature, PrimeSignature
|
||||
)
|
||||
) {
|
||||
override fun execute(data: BytecodeData): PatchResult {
|
||||
// smali patches
|
||||
disablePlayServiceChecks()
|
||||
data.classes.forEach { classDef ->
|
||||
var proxiedClass: MutableClass? = null
|
||||
|
||||
classDef.methods.forEach methodLoop@{ method ->
|
||||
val implementation = method.implementation ?: return@methodLoop
|
||||
|
||||
var proxiedImplementation: MutableMethodImplementation? = null
|
||||
implementation.instructions.forEachIndexed { i, instruction ->
|
||||
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
||||
|
||||
val stringValue = ((instruction as Instruction21c).reference as StringReference).string
|
||||
|
||||
val replaceMode =
|
||||
if (stringValue == "com.google" || stringValue == "com.google.android.gms" ||
|
||||
stringValue.startsWithAny(
|
||||
"com.google.iid",
|
||||
"com.google.android.gms.chimera",
|
||||
"com.google.android.c2dm",
|
||||
) || stringValue.containsAny(
|
||||
"com.google.android.gms.auth.accounts",
|
||||
"com.google.android.gsf",
|
||||
"content://com.google.settings"
|
||||
)
|
||||
) {
|
||||
StringReplaceMode.REPLACE_WITH_MICROG
|
||||
} else if (stringValue.startsWith("com.google.android.gms.chimera.container")) // https://github.com/TeamVanced/VancedMicroG/pull/139/file
|
||||
StringReplaceMode.DO_NOT_REPLACE
|
||||
else if (stringValue.startsWithAny(
|
||||
"com.google.android.youtube.SuggestionsProvider",
|
||||
"com.google.android.youtube.fileprovider"
|
||||
)
|
||||
) {
|
||||
StringReplaceMode.REPLACE_WITH_REVANCED
|
||||
} else {
|
||||
StringReplaceMode.DO_NOT_REPLACE
|
||||
}
|
||||
|
||||
if (replaceMode != StringReplaceMode.DO_NOT_REPLACE) {
|
||||
if (proxiedClass == null) {
|
||||
proxiedClass = data.proxy(classDef).resolve()
|
||||
}
|
||||
|
||||
if (proxiedImplementation == null) {
|
||||
proxiedImplementation = proxiedClass!!.methods.first {
|
||||
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
||||
}.implementation!!
|
||||
}
|
||||
|
||||
val newString = if (replaceMode == StringReplaceMode.REPLACE_WITH_REVANCED) stringValue.replace(
|
||||
"com.google.android.youtube", REVANCED_PACKAGE_NAME
|
||||
)
|
||||
else stringValue.replace("com.google", BASE_MICROG_PACKAGE_NAME)
|
||||
|
||||
proxiedImplementation!!.replaceInstruction(
|
||||
i, BuilderInstruction21c(
|
||||
Opcode.CONST_STRING, instruction.registerA, ImmutableStringReference(newString)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// replace string back
|
||||
val implementation =
|
||||
signatures.elementAt(2).result!!.findParentMethod(@Name("do-not-replace-method") @MatchingMethod(
|
||||
"Llpe;", "c"
|
||||
) @DirectPatternScanMethod @MicroGPatchCompatibility @Version("0.0.1") object : MethodSignature(
|
||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), null, listOf("com.google.android.gms")
|
||||
) {})!!.method.implementation!!
|
||||
|
||||
implementation.replaceInstruction(
|
||||
implementation.instructions.indexOfFirst { it.opcode == Opcode.CONST_STRING },
|
||||
"const-string v0, \"com.google.android.gms\"".toInstruction()
|
||||
)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private fun disablePlayServiceChecks() {
|
||||
for (i in 0 until signatures.count() - 1) {
|
||||
val result = signatures.elementAt(i).result!!
|
||||
val stringInstructions = when (result.immutableMethod.returnType.first()) {
|
||||
'L' -> """
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
"""
|
||||
|
||||
'V' -> "return-void"
|
||||
'I' -> """
|
||||
const/4 v0, 0x0
|
||||
return v0
|
||||
"""
|
||||
|
||||
else -> throw Exception("This case should never happen.")
|
||||
}
|
||||
result.method.implementation!!.addInstructions(
|
||||
0, stringInstructions.trimIndent().toInstructions()
|
||||
)
|
||||
}
|
||||
|
||||
val implementation = signatures.last().result!!.method.implementation!!
|
||||
|
||||
var register = 2
|
||||
val index = implementation.instructions.indexOfFirst {
|
||||
if (it.opcode != Opcode.CONST_STRING) return@indexOfFirst false
|
||||
|
||||
val instructionString = ((it as Instruction21c).reference as StringReference).string
|
||||
if (instructionString != "com.google.android.youtube") return@indexOfFirst false
|
||||
|
||||
register = it.registerA
|
||||
return@indexOfFirst true
|
||||
}
|
||||
|
||||
implementation.replaceInstruction(
|
||||
index, "const-string v$register, \"$REVANCED_PACKAGE_NAME\"".toInstruction()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package app.revanced.patches.youtube.misc.microg.patch.resource
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.implementation.ResourceData
|
||||
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME
|
||||
|
||||
// @Patch TODO: finish patch
|
||||
@Name("microg-resource-patch")
|
||||
@Description("Resource patch to allow YouTube ReVanced to run without root and under a different package name.")
|
||||
@MicroGPatchCompatibility
|
||||
@Version("0.0.1")
|
||||
class MicroGResourcePatch : ResourcePatch() {
|
||||
override fun execute(data: ResourceData): PatchResult {
|
||||
val manifest = data.get("AndroidManifest.xml").readText()
|
||||
|
||||
data.get("AndroidManifest.xml").writeText(
|
||||
manifest.replace(
|
||||
"package=\"com.google.android.youtube\"", "package=\"$REVANCED_PACKAGE_NAME\""
|
||||
).replace(
|
||||
" android:label=\"@string/application_name\" ", " android:label=\"{APP_NAME}\" "
|
||||
).replace(
|
||||
"<uses-permission android:name=\"com.google.android.youtube.permission.C2D_MESSAGE\"",
|
||||
"<uses-permission android:name=\"$REVANCED_PACKAGE_NAME.permission.C2D_MESSAGE\""
|
||||
).replace(
|
||||
"<permission android:name=\"com.google.android.youtube.permission.C2D_MESSAGE\"",
|
||||
"<permission android:name=\"$REVANCED_PACKAGE_NAME.permission.C2D_MESSAGE\""
|
||||
).replace(
|
||||
"<provider android:authorities=\"com.google.android.youtube.lifecycle-trojan\"",
|
||||
"<provider android:authorities=\"$REVANCED_PACKAGE_NAME.lifecycle-trojan\""
|
||||
).replace(
|
||||
"\"com.google.android.youtube.fileprovider\"", "\"$REVANCED_PACKAGE_NAME.fileprovider\""
|
||||
).replace(
|
||||
"<provider android:authorities=\"com.google.android.youtube.photopicker_images\"",
|
||||
"<provider android:authorities=\"$REVANCED_PACKAGE_NAME.photopicker_images\""
|
||||
).replace("com.google.android.c2dm", "$BASE_MICROG_PACKAGE_NAME.android.c2dm").replace(
|
||||
" </queries>",
|
||||
" <package android:name=\"$BASE_MICROG_PACKAGE_NAME.android.gms\"/>\n </queries>"
|
||||
)
|
||||
)
|
||||
|
||||
val replacement = arrayOf(
|
||||
Pair(
|
||||
"com.google.android.youtube.SuggestionProvider", "$REVANCED_PACKAGE_NAME.SuggestionProvider"
|
||||
), Pair(
|
||||
"com.google.android.youtube.fileprovider", "$REVANCED_PACKAGE_NAME.fileprovider"
|
||||
)
|
||||
)
|
||||
|
||||
data.forEach {
|
||||
if (it.extension != "xml") return@forEach
|
||||
|
||||
// TODO: use a reader and only replace strings where needed instead of reading & writing the entire file
|
||||
var content = it.readText()
|
||||
replacement.filter { translation -> content.contains(translation.first) }.forEach { translation ->
|
||||
content = content.replace(translation.first, translation.second)
|
||||
}
|
||||
it.writeText(content)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package app.revanced.patches.youtube.misc.microg.patch.resource.enum
|
||||
|
||||
enum class StringReplaceMode {
|
||||
REPLACE_WITH_MICROG, REPLACE_WITH_REVANCED, DO_NOT_REPLACE
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package app.revanced.patches.youtube.misc.microg.shared
|
||||
|
||||
object Constants {
|
||||
internal const val BASE_MICROG_PACKAGE_NAME = "com.mgoogle"
|
||||
internal const val REVANCED_PACKAGE_NAME = "app.revanced.android.youtube"
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package app.revanced.patches.youtube.misc.microg.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("google-play-utility-signature")
|
||||
@MatchingMethod(
|
||||
"Llss;", "b"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@MicroGPatchCompatibility
|
||||
@Version("0.0.1")
|
||||
object GooglePlayUtilitySignature : MethodSignature(
|
||||
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"), listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.GOTO,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.MONITOR_ENTER,
|
||||
Opcode.SGET_BOOLEAN,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.MONITOR_EXIT,
|
||||
Opcode.GOTO,
|
||||
Opcode.SPUT_BOOLEAN,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_16,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.MONITOR_EXIT,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.SPUT,
|
||||
Opcode.GOTO,
|
||||
Opcode.MOVE_EXCEPTION,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MONITOR_EXIT,
|
||||
Opcode.SGET,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.CONST,
|
||||
Opcode.IF_NE,
|
||||
Opcode.GOTO,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.THROW,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.THROW,
|
||||
Opcode.MOVE_EXCEPTION,
|
||||
Opcode.MONITOR_EXIT,
|
||||
Opcode.THROW,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_4,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.SPUT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_4,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_16,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_16,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_16,
|
||||
Opcode.GOTO_16,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_16,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.GOTO,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.GOTO,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.AGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.AGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.GOTO,
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_GE,
|
||||
Opcode.IGET,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_4,
|
||||
Opcode.GOTO,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.MOVE_EXCEPTION,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.GOTO,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_4,
|
||||
Opcode.GOTO,
|
||||
Opcode.RETURN,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.RETURN
|
||||
), listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms")
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
package app.revanced.patches.youtube.misc.microg.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("google-play-sig-check-signature")
|
||||
@MatchingMethod(
|
||||
"Ldwn;", "d"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@MicroGPatchCompatibility
|
||||
@Version("0.0.1")
|
||||
object IntegrityCheckSignature : MethodSignature(
|
||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"), listOf(
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.SGET,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.CONST_WIDE,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CMP_LONG,
|
||||
Opcode.IF_GEZ,
|
||||
Opcode.CONST_16,
|
||||
Opcode.GOTO_16,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_16,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.MOVE_EXCEPTION,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST,
|
||||
Opcode.IF_NE,
|
||||
Opcode.CONST_16,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.GOTO,
|
||||
Opcode.NEW_ARRAY
|
||||
), listOf("This should never happen.", "GooglePlayServicesUtil", "Google Play Store signature invalid.")
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
package app.revanced.patches.youtube.misc.microg.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||
|
||||
@Name("google-play-prime-signature")
|
||||
@MatchingMethod(
|
||||
"Lpag;", "d"
|
||||
)
|
||||
@DirectPatternScanMethod
|
||||
@MicroGPatchCompatibility
|
||||
@Version("0.0.1")
|
||||
object PrimeSignature : MethodSignature(
|
||||
null, null, null, null, listOf("com.google.android.GoogleCamera", "com.android.vending")
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.youtube.misc.microg.signatures
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
@Name("google-play-service-checker-signature")
|
||||
@MatchingMethod(
|
||||
"Llss;", "d"
|
||||
)
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
@MicroGPatchCompatibility
|
||||
@Version("0.0.1")
|
||||
object ServiceCheckSignature : MethodSignature(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), listOf(
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.THROW,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.THROW,
|
||||
Opcode.RETURN_VOID
|
||||
), listOf("Google Play Services not available")
|
||||
)
|
||||
Reference in New Issue
Block a user