mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 18:03:55 +01:00
Compare commits
92 Commits
v4.4.0-dev
...
v4.8.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6d2cf5a93 | ||
|
|
fe461c1d14 | ||
|
|
6b33cd2d8f | ||
|
|
c727c6f19d | ||
|
|
49db0cee1b | ||
|
|
531955a111 | ||
|
|
e53cc9bba9 | ||
|
|
fc43dd709f | ||
|
|
3a018ff002 | ||
|
|
86f11480e7 | ||
|
|
0190d5a5c9 | ||
|
|
50735fabbc | ||
|
|
653631703c | ||
|
|
2587508944 | ||
|
|
533f9a964d | ||
|
|
fb0b3bd673 | ||
|
|
96e17cf4de | ||
|
|
a7bd0b111e | ||
|
|
7ecd992def | ||
|
|
217d3c69ba | ||
|
|
e329e1dd1a | ||
|
|
6a8b669ba2 | ||
|
|
6fd46ad9b6 | ||
|
|
50ddb680ed | ||
|
|
cc7f79d903 | ||
|
|
57274b5435 | ||
|
|
8295b7a22e | ||
|
|
366f754a6a | ||
|
|
c272333adb | ||
|
|
ef6c00a520 | ||
|
|
58ce37b0d3 | ||
|
|
4b7e12f995 | ||
|
|
2e59965bb5 | ||
|
|
426f405407 | ||
|
|
f85f518fc9 | ||
|
|
f3972d313f | ||
|
|
04a72d52de | ||
|
|
be76e49a8b | ||
|
|
fa1c616014 | ||
|
|
e97aaf4aae | ||
|
|
92c90ec208 | ||
|
|
b4e8beb8ec | ||
|
|
f2fe0d5c6f | ||
|
|
3d3197701c | ||
|
|
1ac612798b | ||
|
|
e1ed1aee69 | ||
|
|
795ccac990 | ||
|
|
da55410a2b | ||
|
|
e7983411a7 | ||
|
|
182748cb16 | ||
|
|
122f04219f | ||
|
|
80763bcef6 | ||
|
|
b80bb8969c | ||
|
|
2a86a670f0 | ||
|
|
dba37b834d | ||
|
|
3ad4eb8dbc | ||
|
|
0e88306f3f | ||
|
|
87cb63f2e7 | ||
|
|
0fead38701 | ||
|
|
19a31019c2 | ||
|
|
61758414c2 | ||
|
|
b4ee8b6da4 | ||
|
|
e86e3d88cf | ||
|
|
8cf444962c | ||
|
|
48bf632dbe | ||
|
|
03e91d4251 | ||
|
|
8caf70719e | ||
|
|
2f28e95252 | ||
|
|
d819e7bbe9 | ||
|
|
fef5f35788 | ||
|
|
80034bc70a | ||
|
|
c40911a815 | ||
|
|
1a53a93cd2 | ||
|
|
2e68c65c9f | ||
|
|
6f8d92827b | ||
|
|
ab2260acfd | ||
|
|
9b3c060acb | ||
|
|
bbc4a6bfa0 | ||
|
|
4df9b9d5b1 | ||
|
|
eebf72f476 | ||
|
|
a27296223f | ||
|
|
77a9a56e2d | ||
|
|
3df3441385 | ||
|
|
86def3efea | ||
|
|
bc9a612824 | ||
|
|
f378ddc6d5 | ||
|
|
7f852e8f32 | ||
|
|
5b7b134d73 | ||
|
|
df9361ea2b | ||
|
|
8c226c4bdc | ||
|
|
c87f8a376d | ||
|
|
cb4b6514db |
34
.github/workflows/pull_strings.yml
vendored
Normal file
34
.github/workflows/pull_strings.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Pull strings
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: 0 0 1 * *
|
||||
|
||||
jobs:
|
||||
pull:
|
||||
name: Pull strings
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Pull strings
|
||||
uses: crowdin/github-action@v1
|
||||
with:
|
||||
config: crowdin.yml
|
||||
download_translations: true
|
||||
localization_branch_name: feat/translations
|
||||
create_pull_request: true
|
||||
pull_request_title: "chore: Sync translations"
|
||||
pull_request_body: "Sync translations from [crowdin.com/project/revanced](https://crowdin.com/project/revanced)"
|
||||
pull_request_base_branch_name: "dev"
|
||||
commit_message: "chore: Sync translations"
|
||||
github_user_name: revanced-bot
|
||||
github_user_email: github@revanced.app
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
27
.github/workflows/push_strings.yml
vendored
Normal file
27
.github/workflows/push_strings.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Push strings
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths:
|
||||
- /src/main/resources/addresources/values/strings.xml
|
||||
|
||||
jobs:
|
||||
push:
|
||||
name: Push strings
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Push strings
|
||||
uses: crowdin/github-action@v1
|
||||
with:
|
||||
config: crowdin.yml
|
||||
upload_sources: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
304
CHANGELOG.md
304
CHANGELOG.md
@@ -1,3 +1,307 @@
|
||||
# [4.8.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.3...v4.8.0-dev.4) (2024-04-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Comments:** Add option to hide timestamp and emoji buttons ([#3076](https://github.com/ReVanced/revanced-patches/issues/3076)) ([7efe5ae](https://github.com/ReVanced/revanced-patches/commit/7efe5aefb252a2ed908907ff218b879e2ad1a331))
|
||||
|
||||
# [4.8.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.2...v4.8.0-dev.3) (2024-04-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Publicize abstract property ([b7c108e](https://github.com/ReVanced/revanced-patches/commit/b7c108ee201c84df31b079f3fecb6cc2f5eaf9f1))
|
||||
|
||||
# [4.8.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.8.0-dev.1...v4.8.0-dev.2) (2024-04-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Case patch option title correctly ([259c8b4](https://github.com/ReVanced/revanced-patches/commit/259c8b4e58df51d92d7e19417e13afa3848afc73))
|
||||
|
||||
# [4.8.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.7.0...v4.8.0-dev.1) (2024-04-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide video action buttons:** Remove obsolete `hide Shop button` ([#3057](https://github.com/ReVanced/revanced-patches/issues/3057)) ([b5e34f3](https://github.com/ReVanced/revanced-patches/commit/b5e34f3aabc1d9df8c41f92251618243caecdc9f))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide Shorts components:** Hide like / dislike button in video ads ([#3062](https://github.com/ReVanced/revanced-patches/issues/3062)) ([1296985](https://github.com/ReVanced/revanced-patches/commit/12969853adfe530eb6006df38e1a5aa30b28fdf9))
|
||||
|
||||
# [4.7.0](https://github.com/ReVanced/revanced-patches/compare/v4.6.0...v4.7.0) (2024-04-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tumblr - Fix old versions:** Improve reliability by removing remnances of Tumblr Live ([#2988](https://github.com/ReVanced/revanced-patches/issues/2988)) ([897b4db](https://github.com/ReVanced/revanced-patches/commit/897b4dbce984270ae1fd7de5bd30bd05153e45f2))
|
||||
* **YouTube - GmsCore support:** Prompt to disable battery optimizations, if not done already ([#2958](https://github.com/ReVanced/revanced-patches/issues/2958)) ([82acb84](https://github.com/ReVanced/revanced-patches/commit/82acb84b5f6ff0722a2eb080b53da9dd3622502f))
|
||||
* **YouTube - Hide ads:** rename `Hide paid content` to `Hide paid promotion label` ([#3026](https://github.com/ReVanced/revanced-patches/issues/3026)) ([17e4ac9](https://github.com/ReVanced/revanced-patches/commit/17e4ac978a2f109fd62469a3163b636cd63c55ae))
|
||||
* **YouTube - Hide load more button:** Include patch with `Hide layout components`, and hide button only in search feed ([#2959](https://github.com/ReVanced/revanced-patches/issues/2959)) ([b007e8e](https://github.com/ReVanced/revanced-patches/commit/b007e8e06a3afad79b40bec1c6a14604f059049c))
|
||||
* **YouTube - Hide Shorts components:** Correctly hide Shorts if navigation tab is changed using device back button ([#3007](https://github.com/ReVanced/revanced-patches/issues/3007)) ([e5848e9](https://github.com/ReVanced/revanced-patches/commit/e5848e99c4cc838595164ef673a77fe60d28086b))
|
||||
* **YouTube - Player flyout menu:** Add hide Lock screen menu ([#2985](https://github.com/ReVanced/revanced-patches/issues/2985)) ([308de4a](https://github.com/ReVanced/revanced-patches/commit/308de4a63ca99b8d30d6b3242f98d6f0e2aefb37))
|
||||
* **YouTube - Spoof device dimensions:** Warn about potential performance issues ([#3039](https://github.com/ReVanced/revanced-patches/issues/3039)) ([9d6f305](https://github.com/ReVanced/revanced-patches/commit/9d6f305b7c923e62b89581d221fedbe1e3f81835))
|
||||
* **YouTube Music - Remove upgrade button:** Fix compatibility with latest versions ([#3045](https://github.com/ReVanced/revanced-patches/issues/3045)) ([80de996](https://github.com/ReVanced/revanced-patches/commit/80de99666555694670529bbfe2e0be7a14d66555))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Hex` patch ([#3034](https://github.com/ReVanced/revanced-patches/issues/3034)) ([3c95aac](https://github.com/ReVanced/revanced-patches/commit/3c95aac838693b354d3a7b0e3dc57c6da5adfa9e))
|
||||
* **Amazon:** Add `Always allow deep-linking` patch ([#3000](https://github.com/ReVanced/revanced-patches/issues/3000)) ([a92b7fb](https://github.com/ReVanced/revanced-patches/commit/a92b7fb43c8b1b45577360cdc6d883fe2815c2f2))
|
||||
* **Strava - Unlock subscription:** Remove compatible version constraint ([80a5599](https://github.com/ReVanced/revanced-patches/commit/80a55991683d7b22626224fa2935a5bf9bfcbfee))
|
||||
* **Twitter:** Add `Sanitize sharing links` patch ([#3003](https://github.com/ReVanced/revanced-patches/issues/3003)) ([186b887](https://github.com/ReVanced/revanced-patches/commit/186b8874157eef1b882b05d491ba1d4ca2809535))
|
||||
* **YouTube - Hide layout components:** Add option to hide horizontal shelves ([#2951](https://github.com/ReVanced/revanced-patches/issues/2951)) ([9ae0650](https://github.com/ReVanced/revanced-patches/commit/9ae0650c0005d882299996aa442410bab4261395))
|
||||
* **YouTube - Hide layout components:** Hide playables ([8423515](https://github.com/ReVanced/revanced-patches/commit/842351548baa33737db09be1cbca9f87c1951341))
|
||||
* **YouTube - Hide Shorts components:** Hide `Shop`, `Location` and `Save sound to playlist` buttons ([#3018](https://github.com/ReVanced/revanced-patches/issues/3018)) ([5210ac4](https://github.com/ReVanced/revanced-patches/commit/5210ac431c191987264865bf8e789ea9f3fdd360))
|
||||
* **YouTube - Hide Shorts components:** Hide tagged products, hide search suggestions ([#3019](https://github.com/ReVanced/revanced-patches/issues/3019)) ([e0d2fe5](https://github.com/ReVanced/revanced-patches/commit/e0d2fe5bd2e681b9a5252a8e4ad582cc019b1606))
|
||||
* **YouTube - Swipe controls:** Save and restore brightness and add auto-brightness toggle ([#2996](https://github.com/ReVanced/revanced-patches/issues/2996)) ([f6c3bc4](https://github.com/ReVanced/revanced-patches/commit/f6c3bc43190d33e06f49b74fc056d26da1bb014a))
|
||||
* **YouTube:** Add 'About' preference to settings menu ([#2981](https://github.com/ReVanced/revanced-patches/issues/2981)) ([5abf894](https://github.com/ReVanced/revanced-patches/commit/5abf89444a3e6a211ec03c242eb9a7847542b08c))
|
||||
* **YouTube:** Match overlay icons style to YouTube ([#3023](https://github.com/ReVanced/revanced-patches/issues/3023)) ([6849393](https://github.com/ReVanced/revanced-patches/commit/684939314be3d0d43482f229b2adb033e7aa492a))
|
||||
* **YouTube:** Support version `19.09.38`, `19.10.39` and `19.11.43` ([#2971](https://github.com/ReVanced/revanced-patches/issues/2971)) ([730f3e3](https://github.com/ReVanced/revanced-patches/commit/730f3e3a7e058b60f9a8130980ecb0a747fa0a8a))
|
||||
* **YT Music - Hide 'Get Music Premium' label:** Remove occurences of label in settings ([#3046](https://github.com/ReVanced/revanced-patches/issues/3046)) ([10e170a](https://github.com/ReVanced/revanced-patches/commit/10e170a7302fdb585efee663ca13c814aea46c54))
|
||||
|
||||
# [4.7.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.15...v4.7.0-dev.16) (2024-04-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Swipe controls:** Save and restore brightness and add auto-brightness toggle ([#2996](https://github.com/ReVanced/revanced-patches/issues/2996)) ([f6c3bc4](https://github.com/ReVanced/revanced-patches/commit/f6c3bc43190d33e06f49b74fc056d26da1bb014a))
|
||||
|
||||
# [4.7.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.14...v4.7.0-dev.15) (2024-04-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Support version `19.09.38`, `19.10.39` and `19.11.43` ([#2971](https://github.com/ReVanced/revanced-patches/issues/2971)) ([730f3e3](https://github.com/ReVanced/revanced-patches/commit/730f3e3a7e058b60f9a8130980ecb0a747fa0a8a))
|
||||
|
||||
# [4.7.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.13...v4.7.0-dev.14) (2024-04-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YT Music - Hide 'Get Music Premium' label:** Remove occurences of label in settings ([#3046](https://github.com/ReVanced/revanced-patches/issues/3046)) ([10e170a](https://github.com/ReVanced/revanced-patches/commit/10e170a7302fdb585efee663ca13c814aea46c54))
|
||||
|
||||
# [4.7.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.12...v4.7.0-dev.13) (2024-04-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music - Remove upgrade button:** Fix compatibility with latest versions ([#3045](https://github.com/ReVanced/revanced-patches/issues/3045)) ([80de996](https://github.com/ReVanced/revanced-patches/commit/80de99666555694670529bbfe2e0be7a14d66555))
|
||||
|
||||
# [4.7.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.11...v4.7.0-dev.12) (2024-04-18)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Hex` patch ([#3034](https://github.com/ReVanced/revanced-patches/issues/3034)) ([3c95aac](https://github.com/ReVanced/revanced-patches/commit/3c95aac838693b354d3a7b0e3dc57c6da5adfa9e))
|
||||
|
||||
# [4.7.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.10...v4.7.0-dev.11) (2024-04-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof device dimensions:** Warn about potential performance issues ([#3039](https://github.com/ReVanced/revanced-patches/issues/3039)) ([9d6f305](https://github.com/ReVanced/revanced-patches/commit/9d6f305b7c923e62b89581d221fedbe1e3f81835))
|
||||
|
||||
# [4.7.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.9...v4.7.0-dev.10) (2024-04-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube:** Add 'About' preference to settings menu ([#2981](https://github.com/ReVanced/revanced-patches/issues/2981)) ([5abf894](https://github.com/ReVanced/revanced-patches/commit/5abf89444a3e6a211ec03c242eb9a7847542b08c))
|
||||
* **YouTube:** Match overlay icons style to YouTube ([#3023](https://github.com/ReVanced/revanced-patches/issues/3023)) ([6849393](https://github.com/ReVanced/revanced-patches/commit/684939314be3d0d43482f229b2adb033e7aa492a))
|
||||
|
||||
# [4.7.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.8...v4.7.0-dev.9) (2024-04-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide ads:** rename `Hide paid content` to `Hide paid promotion label` ([#3026](https://github.com/ReVanced/revanced-patches/issues/3026)) ([17e4ac9](https://github.com/ReVanced/revanced-patches/commit/17e4ac978a2f109fd62469a3163b636cd63c55ae))
|
||||
|
||||
# [4.7.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.7...v4.7.0-dev.8) (2024-04-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide Shorts components:** Hide tagged products, hide search suggestions ([#3019](https://github.com/ReVanced/revanced-patches/issues/3019)) ([e0d2fe5](https://github.com/ReVanced/revanced-patches/commit/e0d2fe5bd2e681b9a5252a8e4ad582cc019b1606))
|
||||
|
||||
# [4.7.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.6...v4.7.0-dev.7) (2024-04-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide layout components:** Hide playables ([8423515](https://github.com/ReVanced/revanced-patches/commit/842351548baa33737db09be1cbca9f87c1951341))
|
||||
|
||||
# [4.7.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.5...v4.7.0-dev.6) (2024-04-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide Shorts components:** Hide `Shop`, `Location` and `Save sound to playlist` buttons ([#3018](https://github.com/ReVanced/revanced-patches/issues/3018)) ([5210ac4](https://github.com/ReVanced/revanced-patches/commit/5210ac431c191987264865bf8e789ea9f3fdd360))
|
||||
|
||||
# [4.7.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.4...v4.7.0-dev.5) (2024-04-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide Shorts components:** Correctly hide Shorts if navigation tab is changed using device back button ([#3007](https://github.com/ReVanced/revanced-patches/issues/3007)) ([e5848e9](https://github.com/ReVanced/revanced-patches/commit/e5848e99c4cc838595164ef673a77fe60d28086b))
|
||||
|
||||
# [4.7.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.3...v4.7.0-dev.4) (2024-04-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Amazon:** Add `Always allow deep-linking` patch ([#3000](https://github.com/ReVanced/revanced-patches/issues/3000)) ([a92b7fb](https://github.com/ReVanced/revanced-patches/commit/a92b7fb43c8b1b45577360cdc6d883fe2815c2f2))
|
||||
* **Twitter:** Add `Sanitize sharing links` patch ([#3003](https://github.com/ReVanced/revanced-patches/issues/3003)) ([186b887](https://github.com/ReVanced/revanced-patches/commit/186b8874157eef1b882b05d491ba1d4ca2809535))
|
||||
|
||||
# [4.7.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.2...v4.7.0-dev.3) (2024-04-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tumblr - Fix old versions:** Improve reliability by removing remnances of Tumblr Live ([#2988](https://github.com/ReVanced/revanced-patches/issues/2988)) ([897b4db](https://github.com/ReVanced/revanced-patches/commit/897b4dbce984270ae1fd7de5bd30bd05153e45f2))
|
||||
|
||||
# [4.7.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.7.0-dev.1...v4.7.0-dev.2) (2024-04-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Strava - Unlock subscription:** Remove compatible version constraint ([80a5599](https://github.com/ReVanced/revanced-patches/commit/80a55991683d7b22626224fa2935a5bf9bfcbfee))
|
||||
|
||||
# [4.7.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.6.1-dev.3...v4.7.0-dev.1) (2024-04-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide layout components:** Add option to hide horizontal shelves ([#2951](https://github.com/ReVanced/revanced-patches/issues/2951)) ([9ae0650](https://github.com/ReVanced/revanced-patches/commit/9ae0650c0005d882299996aa442410bab4261395))
|
||||
|
||||
## [4.6.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.6.1-dev.2...v4.6.1-dev.3) (2024-04-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - GmsCore support:** Prompt to disable battery optimizations, if not done already ([#2958](https://github.com/ReVanced/revanced-patches/issues/2958)) ([82acb84](https://github.com/ReVanced/revanced-patches/commit/82acb84b5f6ff0722a2eb080b53da9dd3622502f))
|
||||
|
||||
## [4.6.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.6.1-dev.1...v4.6.1-dev.2) (2024-04-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide load more button:** Include patch with `Hide layout components`, and hide button only in search feed ([#2959](https://github.com/ReVanced/revanced-patches/issues/2959)) ([b007e8e](https://github.com/ReVanced/revanced-patches/commit/b007e8e06a3afad79b40bec1c6a14604f059049c))
|
||||
|
||||
## [4.6.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.6.0...v4.6.1-dev.1) (2024-04-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Player flyout menu:** Add hide Lock screen menu ([#2985](https://github.com/ReVanced/revanced-patches/issues/2985)) ([308de4a](https://github.com/ReVanced/revanced-patches/commit/308de4a63ca99b8d30d6b3242f98d6f0e2aefb37))
|
||||
|
||||
# [4.6.0](https://github.com/ReVanced/revanced-patches/compare/v4.5.0...v4.6.0) (2024-04-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Mi Fitness - Fix login:** Patch correct register ([#2942](https://github.com/ReVanced/revanced-patches/issues/2942)) ([dc96942](https://github.com/ReVanced/revanced-patches/commit/dc969422b5d50f21e6ea7a64b67dfc650fee6e36))
|
||||
* **Tumblr:** Restore compatibility with latest versions ([#2955](https://github.com/ReVanced/revanced-patches/issues/2955)) ([2954ba7](https://github.com/ReVanced/revanced-patches/commit/2954ba78d21d77308404961f79234bbec606d42e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Tumblr:** Add `Fix old versions` patch ([#2954](https://github.com/ReVanced/revanced-patches/issues/2954)) ([2fde60e](https://github.com/ReVanced/revanced-patches/commit/2fde60eceb0a96fa857c32cd55c1fd7fe776a679))
|
||||
|
||||
# [4.6.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.5.1-dev.2...v4.6.0-dev.1) (2024-03-31)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Tumblr:** Add `Fix old versions` patch ([#2954](https://github.com/ReVanced/revanced-patches/issues/2954)) ([2fde60e](https://github.com/ReVanced/revanced-patches/commit/2fde60eceb0a96fa857c32cd55c1fd7fe776a679))
|
||||
|
||||
## [4.5.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.5.1-dev.1...v4.5.1-dev.2) (2024-03-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Mi Fitness - Fix login:** Patch correct register ([#2942](https://github.com/ReVanced/revanced-patches/issues/2942)) ([dc96942](https://github.com/ReVanced/revanced-patches/commit/dc969422b5d50f21e6ea7a64b67dfc650fee6e36))
|
||||
|
||||
## [4.5.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.5.0...v4.5.1-dev.1) (2024-03-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tumblr:** Restore compatibility with latest versions ([#2955](https://github.com/ReVanced/revanced-patches/issues/2955)) ([2954ba7](https://github.com/ReVanced/revanced-patches/commit/2954ba78d21d77308404961f79234bbec606d42e))
|
||||
|
||||
# [4.5.0](https://github.com/ReVanced/revanced-patches/compare/v4.4.0...v4.5.0) (2024-03-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Alternative thumbnails:** Selectively enable for home / subscription / search ([#2926](https://github.com/ReVanced/revanced-patches/issues/2926)) ([8549e1b](https://github.com/ReVanced/revanced-patches/commit/8549e1ba58ad1e1608f5e3ceacd31eeb94578949))
|
||||
* **YouTube - GmsCore:** Require ignoring battery optimizations ([#2952](https://github.com/ReVanced/revanced-patches/issues/2952)) ([c0bef25](https://github.com/ReVanced/revanced-patches/commit/c0bef255909ca884838675ca6f7ac5b0e2e21730))
|
||||
|
||||
# [4.5.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.5.0-dev.1...v4.5.0-dev.2) (2024-03-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - GmsCore:** Require ignoring battery optimizations ([#2952](https://github.com/ReVanced/revanced-patches/issues/2952)) ([c0bef25](https://github.com/ReVanced/revanced-patches/commit/c0bef255909ca884838675ca6f7ac5b0e2e21730))
|
||||
|
||||
# [4.5.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.4.0...v4.5.0-dev.1) (2024-03-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Alternative thumbnails:** Selectively enable for home / subscription / search ([#2926](https://github.com/ReVanced/revanced-patches/issues/2926)) ([8549e1b](https://github.com/ReVanced/revanced-patches/commit/8549e1ba58ad1e1608f5e3ceacd31eeb94578949))
|
||||
|
||||
# [4.4.0](https://github.com/ReVanced/revanced-patches/compare/v4.3.0...v4.4.0) (2024-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **TikTok:** Hook application context earlier to prevent crash ([#2893](https://github.com/ReVanced/revanced-patches/issues/2893)) ([395ccda](https://github.com/ReVanced/revanced-patches/commit/395ccda7b9218c522c7ca0f99f75a12036d3e3f3))
|
||||
* **YouTube - Client spoof:** Spoof all user agents ([44a8a13](https://github.com/ReVanced/revanced-patches/commit/44a8a1399897caaff3ff45db8549ddedb2f01b68))
|
||||
* **YouTube - Downloads:** Use new task context ([#2841](https://github.com/ReVanced/revanced-patches/issues/2841)) ([6d88cb4](https://github.com/ReVanced/revanced-patches/commit/6d88cb49ec739700866290babcba5fb3032dbced))
|
||||
* **YouTube - Hide ads:** Prevent app crash if hiding fullscreen ads is not possible ([#2910](https://github.com/ReVanced/revanced-patches/issues/2910)) ([9f50470](https://github.com/ReVanced/revanced-patches/commit/9f50470bf6582fe2f20a903a97bf66c41f296fb2))
|
||||
* **YouTube Music:** Fix compatibility with latest versions ([#2924](https://github.com/ReVanced/revanced-patches/issues/2924)) ([8378c84](https://github.com/ReVanced/revanced-patches/commit/8378c8481634a63a5568480475757e64b7ec466e))
|
||||
* **YouTube:** Fix video playback by switching to ReVanced GmsCore vendor ([#2907](https://github.com/ReVanced/revanced-patches/issues/2907)) ([33ea122](https://github.com/ReVanced/revanced-patches/commit/33ea12228c2ae5dcadf3e7c7016d4bf6006d899a))
|
||||
* **YouTube:** Move setting to correct screen ([a16eda8](https://github.com/ReVanced/revanced-patches/commit/a16eda864515612d3a6b846082844df15eb49f56))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Instagram - Hide timeline ads:** Make compatible with latest versions ([a212f29](https://github.com/ReVanced/revanced-patches/commit/a212f29bd33bb5e10f024e058d26e20ee926190b))
|
||||
* **Mi Fitness:** Add `Force English locale` and `Fix login` patch ([#2734](https://github.com/ReVanced/revanced-patches/issues/2734)) ([7a25791](https://github.com/ReVanced/revanced-patches/commit/7a25791d53530b1236896b2c3d6275ee7556e8b7))
|
||||
* **Sync for Lemmy:** Add `Disable ads` patch ([#2872](https://github.com/ReVanced/revanced-patches/issues/2872)) ([0785819](https://github.com/ReVanced/revanced-patches/commit/0785819dd5ad487c778b5baf09004cdab3687184))
|
||||
* **YouTube - Downloads:** Use external downloader when selecting 'Download' in home feed flyout menu ([#2881](https://github.com/ReVanced/revanced-patches/issues/2881)) ([10afc8c](https://github.com/ReVanced/revanced-patches/commit/10afc8cc71ff29fea4937fb12fd3d1edf9c581f5))
|
||||
* **YouTube - External downloader:** Add ability to use in-app download button ([d900011](https://github.com/ReVanced/revanced-patches/commit/d9000113a905c14f8409aa75008f1ef6a1aecd0c))
|
||||
* **YouTube - Hide layout components:** Filter home/search results by keywords ([#2853](https://github.com/ReVanced/revanced-patches/issues/2853)) ([5916204](https://github.com/ReVanced/revanced-patches/commit/59162042b0a68edf7f94a3c21f838dada3c3f9c3))
|
||||
* **YouTube - Hide Shorts components:** Hide like and dislike buttons ([2df0892](https://github.com/ReVanced/revanced-patches/commit/2df0892682406e67283c4aeaacebf8f222029833))
|
||||
* **YouTube - Hide Shorts components:** Hide sound metadata label ([ea7d1e0](https://github.com/ReVanced/revanced-patches/commit/ea7d1e0d08cc245117ffe8ad0df3c31c5e87f739))
|
||||
* **YouTube - Hide Shorts components:** Hide title and full video link label ([e7b64e1](https://github.com/ReVanced/revanced-patches/commit/e7b64e154e7fb8edd0037f5e171f4aa3ed9017f8))
|
||||
* **YouTube - Hide Shorts components:** Selectively hide Shorts for home / subscription / search ([#2925](https://github.com/ReVanced/revanced-patches/issues/2925)) ([497c067](https://github.com/ReVanced/revanced-patches/commit/497c067e80e560eb125f5fc30eef9763929b4ee4))
|
||||
* **YouTube :** Remove `HDR auto brightness` patch ([#2863](https://github.com/ReVanced/revanced-patches/issues/2863)) ([b4c7bf4](https://github.com/ReVanced/revanced-patches/commit/b4c7bf48084184e5f031f7f5139a9a29341d8ebf))
|
||||
* **YouTube Vanced:** Remove `Hide ads` patch ([87887e4](https://github.com/ReVanced/revanced-patches/commit/87887e4163dd9e242209f4d0fefb415f9bc7ca75))
|
||||
* **YouTube:** Support version `19.05`, `19.06`, `19.07`, `19.08` and `19.09` ([#2862](https://github.com/ReVanced/revanced-patches/issues/2862)) ([f044dde](https://github.com/ReVanced/revanced-patches/commit/f044dde054861ff16846a6be6287f86fa3afb3d8))
|
||||
|
||||
# [4.4.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.4.0-dev.14...v4.4.0-dev.15) (2024-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music:** Fix compatibility with latest versions ([#2924](https://github.com/ReVanced/revanced-patches/issues/2924)) ([8378c84](https://github.com/ReVanced/revanced-patches/commit/8378c8481634a63a5568480475757e64b7ec466e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide Shorts components:** Selectively hide Shorts for home / subscription / search ([#2925](https://github.com/ReVanced/revanced-patches/issues/2925)) ([497c067](https://github.com/ReVanced/revanced-patches/commit/497c067e80e560eb125f5fc30eef9763929b4ee4))
|
||||
|
||||
# [4.4.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.4.0-dev.13...v4.4.0-dev.14) (2024-03-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Hide layout components:** Filter home/search results by keywords ([#2853](https://github.com/ReVanced/revanced-patches/issues/2853)) ([5916204](https://github.com/ReVanced/revanced-patches/commit/59162042b0a68edf7f94a3c21f838dada3c3f9c3))
|
||||
|
||||
# [4.4.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.4.0-dev.12...v4.4.0-dev.13) (2024-03-26)
|
||||
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggin
|
||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/hex/HexPatch : app/revanced/patches/shared/misc/hex/BaseHexPatch {
|
||||
public fun <init> ()V
|
||||
public fun getReplacements ()Ljava/util/List;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/misc/network/OverrideCertificatePinningPatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
@@ -152,6 +157,12 @@ public final class app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryP
|
||||
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Pair;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/amazon/deeplinking/DeepLinkingPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/amazon/deeplinking/DeepLinkingPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/backdrops/misc/pro/ProUnlockPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/backdrops/misc/pro/ProUnlockPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -302,6 +313,12 @@ public final class app/revanced/patches/moneymanager/UnlockProPatch : app/revanc
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/ad/video/HideMusicVideoAds : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/ad/video/HideMusicVideoAds;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/ad/video/MusicVideoAdsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/ad/video/MusicVideoAdsPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -314,6 +331,12 @@ public final class app/revanced/patches/music/audio/codecs/CodecsUnlockPatch : a
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/audio/exclusiveaudio/EnableExclusiveAudioPlayback : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/audio/exclusiveaudio/EnableExclusiveAudioPlayback;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/audio/exclusiveaudio/ExclusiveAudioPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/audio/exclusiveaudio/ExclusiveAudioPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -326,6 +349,12 @@ public final class app/revanced/patches/music/interaction/permanentrepeat/Perman
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/interaction/permanentshuffle/PermanentShufflePatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/interaction/permanentshuffle/PermanentShuffleTogglePatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/interaction/permanentshuffle/PermanentShuffleTogglePatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -338,6 +367,12 @@ public final class app/revanced/patches/music/layout/compactheader/CompactHeader
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/layout/compactheader/HideCategoryBar : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/layout/compactheader/HideCategoryBar;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/layout/minimizedplayback/MinimizedPlaybackPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/layout/minimizedplayback/MinimizedPlaybackPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -639,6 +674,22 @@ public abstract class app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportRes
|
||||
protected final fun getGmsCoreVendorGroupId ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/shared/misc/hex/BaseHexPatch : app/revanced/patcher/patch/RawResourcePatch {
|
||||
public fun <init> ()V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
public abstract fun getReplacements ()Ljava/util/List;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/misc/hex/BaseHexPatch$Replacement {
|
||||
public static final field Companion Lapp/revanced/patches/shared/misc/hex/BaseHexPatch$Replacement$Companion;
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public final fun replacePattern ([B)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/misc/hex/BaseHexPatch$Replacement$Companion {
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public fun <init> (Ljava/lang/String;Ljava/util/Set;)V
|
||||
public fun <init> (Ljava/util/Set;)V
|
||||
@@ -675,6 +726,7 @@ public final class app/revanced/patches/shared/misc/mapping/ResourceMappingPatch
|
||||
public static final field INSTANCE Lapp/revanced/patches/shared/misc/mapping/ResourceMappingPatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
public final fun get (Ljava/lang/String;Ljava/lang/String;)J
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/misc/mapping/ResourceMappingPatch$ResourceElement {
|
||||
@@ -814,6 +866,8 @@ public final class app/revanced/patches/shared/misc/settings/preference/ListPref
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference : app/revanced/patches/shared/misc/settings/preference/BasePreference {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getSelectable ()Z
|
||||
@@ -1032,6 +1086,12 @@ public final class app/revanced/patches/tumblr/featureflags/OverrideFeatureFlags
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/tumblr/fixes/FixOldVersionsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/tumblr/fixes/FixOldVersionsPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/tumblr/live/DisableTumblrLivePatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/tumblr/live/DisableTumblrLivePatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1166,6 +1226,12 @@ public final class app/revanced/patches/twitter/misc/links/OpenLinksWithAppChoos
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/twitter/misc/links/SanitizeSharingLinksPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/twitter/misc/links/SanitizeSharingLinksPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/vsco/misc/pro/UnlockProPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/vsco/misc/pro/UnlockProPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1609,6 +1675,13 @@ public final class app/revanced/patches/youtube/misc/minimizedplayback/Minimized
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/navigation/NavigationBarHookPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public final fun getHookNavigationButtonCreated ()Lkotlin/jvm/functions/Function1;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch : app/revanced/patcher/patch/ResourcePatch, java/io/Closeable {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch;
|
||||
public final fun addControls (Ljava/lang/String;)V
|
||||
@@ -1776,11 +1849,12 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat
|
||||
|
||||
public final class app/revanced/util/BytecodeUtilsKt {
|
||||
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
|
||||
public static final fun findIndexForIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException;
|
||||
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I
|
||||
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||
public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
|
||||
public static final fun resultOrThrow (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
|
||||
public static final fun returnEarly (Ljava/util/List;Z)V
|
||||
|
||||
@@ -15,7 +15,7 @@ repositories {
|
||||
mavenLocal()
|
||||
google()
|
||||
maven {
|
||||
// A repository must be speficied for some reason. "registry" is a dummy.
|
||||
// A repository must be specified for some reason. "registry" is a dummy.
|
||||
url = uri("https://maven.pkg.github.com/revanced/registry")
|
||||
credentials {
|
||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
||||
|
||||
8
crowdin.yml
Normal file
8
crowdin.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
project_id_env: "CROWDIN_PROJECT_ID"
|
||||
api_token_env: "CROWDIN_PERSONAL_TOKEN"
|
||||
|
||||
preserve_hierarchy: false
|
||||
files:
|
||||
- source: src/main/resources/addresources/values/strings.xml
|
||||
translation: src/main/resources/addresources/values-%android_code%/strings.xml
|
||||
skip_untranslated_strings: true
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
kotlin.code.style = official
|
||||
version = 4.4.0-dev.13
|
||||
version = 4.8.0-dev.4
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package app.revanced.patches.all.misc.hex
|
||||
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.registerNewPatchOption
|
||||
import app.revanced.patches.shared.misc.hex.BaseHexPatch
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.patcher.patch.Patch as PatchClass
|
||||
|
||||
@Patch(
|
||||
name = "Hex",
|
||||
description = "Replaces a hexadecimal patterns of bytes of files in an APK.",
|
||||
use = false,
|
||||
)
|
||||
@Suppress("unused")
|
||||
class HexPatch : BaseHexPatch() {
|
||||
// TODO: Instead of stringArrayOption, use a custom option type to work around
|
||||
// https://github.com/ReVanced/revanced-library/issues/48.
|
||||
// Replace the custom option type with a stringArrayOption once the issue is resolved.
|
||||
private val replacementsOption by registerNewPatchOption<PatchClass<*>, List<String>>(
|
||||
key = "replacements",
|
||||
title = "Replacements",
|
||||
description = """
|
||||
Hexadecimal patterns to search for and replace with another in a target file.
|
||||
|
||||
A pattern is a sequence of case insensitive strings, each representing hexadecimal bytes, separated by spaces.
|
||||
An example pattern is 'aa 01 02 FF'.
|
||||
|
||||
Every pattern must be followed by a pipe ('|'), the replacement pattern,
|
||||
another pipe ('|'), and the path to the file to make the changes in relative to the APK root.
|
||||
The replacement pattern must have the same length as the original pattern.
|
||||
|
||||
Full example of a valid input:
|
||||
'aa 01 02 FF|00 00 00 00|path/to/file'
|
||||
""".trimIndentMultiline(),
|
||||
required = true,
|
||||
valueType = "StringArray",
|
||||
)
|
||||
|
||||
override val replacements
|
||||
get() = replacementsOption!!.map { from ->
|
||||
val (pattern, replacementPattern, targetFilePath) = try {
|
||||
from.split("|", limit = 3)
|
||||
} catch (e: Exception) {
|
||||
throw PatchException(
|
||||
"Invalid input: $from.\n" +
|
||||
"Every pattern must be followed by a pipe ('|'), " +
|
||||
"the replacement pattern, another pipe ('|'), " +
|
||||
"and the path to the file to make the changes in relative to the APK root. ",
|
||||
)
|
||||
}
|
||||
|
||||
Replacement(pattern, replacementPattern, targetFilePath)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.amazon.deeplinking
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object DeepLinkingFingerprint : MethodFingerprint(
|
||||
"Z",
|
||||
parameters = listOf("L"),
|
||||
accessFlags = AccessFlags.PRIVATE.value,
|
||||
strings = listOf("https://www.", "android.intent.action.VIEW")
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
package app.revanced.patches.amazon.deeplinking
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Always allow deep-linking",
|
||||
description = "Open Amazon links, even if the app is not set to handle Amazon links.",
|
||||
compatiblePackages = [CompatiblePackage("com.amazon.mShop.android.shopping")]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object DeepLinkingPatch : BytecodePatch(
|
||||
setOf(DeepLinkingFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
DeepLinkingFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
"""
|
||||
) ?: throw DeepLinkingFingerprint.exception
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,11 @@ package app.revanced.patches.mifitness.misc.login
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.mifitness.misc.login.fingerprints.XiaomiAccountManagerConstructorFingerprint
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
name = "Fix login",
|
||||
@@ -20,16 +18,9 @@ object FixLoginPatch : BytecodePatch(
|
||||
setOf(XiaomiAccountManagerConstructorFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
XiaomiAccountManagerConstructorFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val isCertifiedIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val isCertifiedRegister = getInstruction<OneRegisterInstruction>(isCertifiedIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
isCertifiedIndex,
|
||||
"const/4 p$isCertifiedRegister, 0x0",
|
||||
)
|
||||
}
|
||||
} ?: throw XiaomiAccountManagerConstructorFingerprint.exception
|
||||
XiaomiAccountManagerConstructorFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"const/16 p2, 0x0",
|
||||
) ?: throw XiaomiAccountManagerConstructorFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package app.revanced.patches.mifitness.misc.login.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object XiaomiAccountManagerConstructorFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR,
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass == "Lcom/xiaomi/passport/accountmanager/XiaomiAccountManager;"
|
||||
},
|
||||
opcodes = listOf(Opcode.IF_NEZ),
|
||||
parameters = listOf(
|
||||
"Landroid/content/Context;",
|
||||
"Z",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.music.ad.video
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsParentFingerprint
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Hide music video ads",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object HideMusicVideoAds : BytecodePatch(
|
||||
setOf(ShowMusicVideoAdsParentFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
ShowMusicVideoAdsParentFingerprint.result?.let {
|
||||
val showMusicVideoAdsMethod = context
|
||||
.toMethodWalker(it.mutableMethod)
|
||||
.nextMethod(it.scanResult.patternScanResult!!.startIndex + 1, true).getMethod() as MutableMethod
|
||||
|
||||
showMusicVideoAdsMethod.addInstruction(0, "const/4 p1, 0x0")
|
||||
} ?: throw ShowMusicVideoAdsParentFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("This patch class has been renamed to HideMusicVideoAds.")
|
||||
object MusicVideoAdsPatch : BytecodePatch(
|
||||
dependencies = setOf(HideMusicVideoAds::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package app.revanced.patches.music.ad.video
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint
|
||||
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint
|
||||
|
||||
@Patch(
|
||||
name = "Music video ads",
|
||||
description = "Removes ads in the music player.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object MusicVideoAdsPatch : BytecodePatch(
|
||||
setOf(ShowMusicVideoAdsConstructorFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef)
|
||||
|
||||
val result = ShowMusicVideoAdsFingerprint.result!!
|
||||
|
||||
result.mutableMethod.addInstruction(
|
||||
result.scanResult.patternScanResult!!.startIndex,
|
||||
"""
|
||||
const/4 p1, 0x0
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package app.revanced.patches.music.ad.video.fingerprints
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
internal object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint(
|
||||
"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,
|
||||
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
|
||||
)
|
||||
)
|
||||
@@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.music.ad.video.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object ShowMusicVideoAdsFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf(
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.music.ad.video.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object ShowMusicVideoAdsParentFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
),
|
||||
strings = listOf("maybeRegenerateCpnAndStatsClient called unexpectedly, but no error."),
|
||||
)
|
||||
@@ -10,13 +10,12 @@ import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprin
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
@Patch(
|
||||
name = "Codecs unlock",
|
||||
description = "Adds more audio codec options. The new audio codecs usually result in better audio quality.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
@Deprecated("This patch is no longer needed as the feature is now enabled by default.")
|
||||
object CodecsUnlockPatch : BytecodePatch(
|
||||
setOf(CodecsLockFingerprint, AllCodecsReferenceFingerprint)
|
||||
setOf(CodecsLockFingerprint, AllCodecsReferenceFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val codecsLockResult = CodecsLockFingerprint.result!!
|
||||
@@ -25,13 +24,13 @@ object CodecsUnlockPatch : BytecodePatch(
|
||||
|
||||
val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex
|
||||
val instructionIndex = scanResultStartIndex +
|
||||
if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) {
|
||||
// for 5.16.xx and lower
|
||||
-3
|
||||
} else {
|
||||
// since 5.17.xx
|
||||
-2
|
||||
}
|
||||
if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) {
|
||||
// for 5.16.xx and lower
|
||||
-3
|
||||
} else {
|
||||
// since 5.17.xx
|
||||
-2
|
||||
}
|
||||
|
||||
val allCodecsResult = AllCodecsReferenceFingerprint.result!!
|
||||
val allCodecsMethod =
|
||||
@@ -41,7 +40,7 @@ object CodecsUnlockPatch : BytecodePatch(
|
||||
|
||||
implementation.replaceInstruction(
|
||||
instructionIndex,
|
||||
"invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction()
|
||||
"invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
package app.revanced.patches.music.audio.exclusiveaudio
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AllowExclusiveAudioPlaybackFingerprint
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Exclusive audio playback",
|
||||
name = "Enable exclusive audio playback",
|
||||
description = "Enables the option to play audio without video.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object ExclusiveAudioPatch : BytecodePatch(
|
||||
setOf(AllowExclusiveAudioPlaybackFingerprint)
|
||||
object EnableExclusiveAudioPlayback : BytecodePatch(
|
||||
setOf(AllowExclusiveAudioPlaybackFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AllowExclusiveAudioPlaybackFingerprint.result?.mutableMethod?.apply {
|
||||
addInstructions(
|
||||
0,
|
||||
"""
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
"""
|
||||
""",
|
||||
)
|
||||
} ?: throw AllowExclusiveAudioPlaybackFingerprint.exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("This patch class has been renamed to EnableExclusiveAudioPlayback.")
|
||||
object ExclusiveAudioPatch : BytecodePatch(emptySet()) {
|
||||
override fun execute(context: BytecodeContext) = EnableExclusiveAudioPlayback.execute(context)
|
||||
}
|
||||
@@ -1,25 +1,32 @@
|
||||
package app.revanced.patches.music.interaction.permanentshuffle
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.interaction.permanentshuffle.fingerprints.DisableShuffleFingerprint
|
||||
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Permanent shuffle",
|
||||
description = "Permanently remember your shuffle preference " +
|
||||
"even if the playlist ends or another track is played.",
|
||||
"even if the playlist ends or another track is played.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
use = false
|
||||
use = false,
|
||||
)
|
||||
@Suppress("unused")
|
||||
object PermanentShuffleTogglePatch : BytecodePatch(setOf(DisableShuffleFingerprint)) {
|
||||
object PermanentShufflePatch : BytecodePatch(setOf(DisableShuffleFingerprint)) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
DisableShuffleFingerprint.result?.mutableMethod?.addInstruction(0, "return-void")
|
||||
?: throw DisableShuffleFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("This patch class has been renamed to PermanentShufflePatch.")
|
||||
object PermanentShuffleTogglePatch : BytecodePatch(
|
||||
dependencies = setOf(PermanentShufflePatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction11x
|
||||
|
||||
@Patch(
|
||||
name = "Compact header",
|
||||
description = "Hides the music category bar at the top of the homepage.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
use = false
|
||||
)
|
||||
@Suppress("unused")
|
||||
object CompactHeaderPatch : BytecodePatch(
|
||||
setOf(CompactHeaderConstructorFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val result = CompactHeaderConstructorFingerprint.result!!
|
||||
val method = result.mutableMethod
|
||||
|
||||
val insertIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA
|
||||
method.addInstructions(
|
||||
insertIndex, """
|
||||
const/16 v2, 0x8
|
||||
invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.layout.compactheader.fingerprints.ConstructCategoryBarFingerprint
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
name = "Hide category bar",
|
||||
description = "Hides the category bar at the top of the homepage.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
use = false,
|
||||
)
|
||||
@Suppress("unused")
|
||||
object HideCategoryBar : BytecodePatch(
|
||||
setOf(ConstructCategoryBarFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
ConstructCategoryBarFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"""
|
||||
const/16 v2, 0x8
|
||||
invoke-virtual {v$register, v2}, Landroid/view/View;->setVisibility(I)V
|
||||
""",
|
||||
)
|
||||
}
|
||||
} ?: throw ConstructCategoryBarFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("This patch class has been renamed to HideCategoryBar.")
|
||||
object CompactHeaderPatch : BytecodePatch(
|
||||
dependencies = setOf(HideCategoryBar::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,19 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object CompactHeaderConstructorFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
internal object ConstructCategoryBarFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
listOf("Landroid/content/Context;", "L", "L", "L"),
|
||||
listOf(
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST
|
||||
)
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
),
|
||||
)
|
||||
@@ -1,26 +1,39 @@
|
||||
package app.revanced.patches.music.layout.minimizedplayback
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
|
||||
|
||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.BackgroundPlaybackDisableFingerprint
|
||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Minimized playback music",
|
||||
description = "Enables minimized playback on Kids music.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
name = "Minimized playback",
|
||||
description = "Unlocks options for picture-in-picture and background playback.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object MinimizedPlaybackPatch : BytecodePatch(setOf(MinimizedPlaybackManagerFingerprint)) {
|
||||
override fun execute(context: BytecodeContext) =
|
||||
MinimizedPlaybackManagerFingerprint.result?.mutableMethod?.addInstruction(
|
||||
object MinimizedPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint,
|
||||
BackgroundPlaybackDisableFingerprint,
|
||||
),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"return-void",
|
||||
) ?: throw KidsMinimizedPlaybackPolicyControllerFingerprint.exception
|
||||
|
||||
BackgroundPlaybackDisableFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
return-void
|
||||
"""
|
||||
) ?: throw MinimizedPlaybackManagerFingerprint.exception
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""",
|
||||
) ?: throw BackgroundPlaybackDisableFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
|
||||
"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,
|
||||
),
|
||||
)
|
||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
|
||||
internal object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("I", "L", "Z"),
|
||||
@@ -22,5 +22,5 @@ internal object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NE,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
)
|
||||
),
|
||||
)
|
||||
@@ -2,41 +2,57 @@ package app.revanced.patches.music.layout.premium
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint
|
||||
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint
|
||||
import app.revanced.patches.music.layout.premium.fingerprints.MembershipSettingsFingerprint
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
name = "Hide get premium",
|
||||
description = "Removes all \"Get Premium\" evidences from the avatar menu.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
name = "Hide 'Get Music Premium' label",
|
||||
description = "Hides the \"Get Music Premium\" label from the account menu and settings.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object HideGetPremiumPatch : BytecodePatch(setOf(HideGetPremiumParentFingerprint)) {
|
||||
object HideGetPremiumPatch : BytecodePatch(
|
||||
setOf(
|
||||
HideGetPremiumFingerprint,
|
||||
MembershipSettingsFingerprint,
|
||||
),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val parentResult = HideGetPremiumParentFingerprint.result!!
|
||||
HideGetPremiumFingerprint.resolve(context, parentResult.classDef)
|
||||
HideGetPremiumFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
val startIndex = parentResult.scanResult.patternScanResult!!.startIndex
|
||||
val setVisibilityInstruction = getInstruction<FiveRegisterInstruction>(insertIndex)
|
||||
val getPremiumViewRegister = setVisibilityInstruction.registerC
|
||||
val visibilityRegister = setVisibilityInstruction.registerD
|
||||
|
||||
val parentMethod = parentResult.mutableMethod
|
||||
parentMethod.replaceInstruction(
|
||||
startIndex,
|
||||
"""
|
||||
const/4 v1, 0x0
|
||||
"""
|
||||
)
|
||||
replaceInstruction(
|
||||
insertIndex,
|
||||
"const/16 v$visibilityRegister, 0x8",
|
||||
)
|
||||
|
||||
val result = HideGetPremiumFingerprint.result!!
|
||||
val method = result.mutableMethod
|
||||
method.addInstruction(
|
||||
startIndex,
|
||||
addInstruction(
|
||||
insertIndex + 1,
|
||||
"invoke-virtual {v$getPremiumViewRegister, v$visibilityRegister}, " +
|
||||
"Landroid/view/View;->setVisibility(I)V",
|
||||
)
|
||||
}
|
||||
} ?: throw HideGetPremiumFingerprint.exception
|
||||
|
||||
MembershipSettingsFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/16 v0, 0x8
|
||||
"""
|
||||
)
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
""",
|
||||
) ?: throw MembershipSettingsFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,15 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object HideGetPremiumFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf(),
|
||||
listOf(
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.CONST_16,
|
||||
Opcode.GOTO,
|
||||
Opcode.NOP,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
)
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
),
|
||||
listOf("FEmusic_history", "FEmusic_offline"),
|
||||
)
|
||||
|
||||
@@ -5,15 +5,16 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object HideGetPremiumParentFingerprint : MethodFingerprint(
|
||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
internal object MembershipSettingsFingerprint : MethodFingerprint(
|
||||
returnType = "Ljava/lang/CharSequence;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC
|
||||
),
|
||||
listOf("FEmusic_history"),
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_OBJECT
|
||||
)
|
||||
)
|
||||
@@ -1,71 +1,84 @@
|
||||
package app.revanced.patches.music.layout.upgradebutton
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.newLabel
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
@Patch(
|
||||
name = "Remove upgrade button",
|
||||
description = "Removes the upgrade tab from the pivot bar.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object RemoveUpgradeButtonPatch : BytecodePatch(
|
||||
setOf(PivotBarConstructorFingerprint)
|
||||
setOf(PivotBarConstructorFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val result = PivotBarConstructorFingerprint.result!!
|
||||
val implementation = result.mutableMethod.implementation!!
|
||||
PivotBarConstructorFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val pivotBarElementFieldReference = getInstruction(it.scanResult.patternScanResult!!.endIndex - 1)
|
||||
.getReference<FieldReference>()
|
||||
|
||||
val pivotBarElementFieldRef =
|
||||
(implementation.instructions[result.scanResult.patternScanResult!!.endIndex - 1] as Instruction22c).reference
|
||||
val register = (getInstructions().first() as Instruction35c).registerC
|
||||
|
||||
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, 0x4
|
||||
invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
|
||||
iput-object v0, v$register, $pivotBarElementFieldRef
|
||||
""".toInstructions().toMutableList()
|
||||
// First compile all the needed instructions.
|
||||
val instructionList = """
|
||||
invoke-interface { v0 }, Ljava/util/List;->size()I
|
||||
move-result v1
|
||||
const/4 v2, 0x4
|
||||
invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
|
||||
iput-object v0, v$register, $pivotBarElementFieldReference
|
||||
""".toInstructions().toMutableList()
|
||||
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
val endIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
// Replace the instruction to retain the label at given index.
|
||||
replaceInstruction(
|
||||
endIndex - 1,
|
||||
instructionList[0], // invoke-interface.
|
||||
)
|
||||
// Do not forget to remove this instruction since we added it already.
|
||||
instructionList.removeFirst()
|
||||
|
||||
// replace the instruction to retain the label at given index
|
||||
implementation.replaceInstruction(
|
||||
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
|
||||
addInstruction(
|
||||
endIndex,
|
||||
exitInstruction,
|
||||
)
|
||||
// Do not forget to remove this instruction since we added it already.
|
||||
instructionList.removeLast()
|
||||
|
||||
val exitInstruction = instructionList.last() // iput-object
|
||||
implementation.addInstruction(
|
||||
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,
|
||||
newLabel(endIndex),
|
||||
),
|
||||
)
|
||||
|
||||
// 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(endIndex)
|
||||
)
|
||||
)
|
||||
|
||||
implementation.addInstructions(
|
||||
endIndex, instructionList
|
||||
)
|
||||
addInstructions(
|
||||
endIndex,
|
||||
instructionList,
|
||||
)
|
||||
}
|
||||
} ?: throw PivotBarConstructorFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,20 @@
|
||||
package app.revanced.patches.music.layout.upgradebutton.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
internal object PivotBarConstructorFingerprint : MethodFingerprint(
|
||||
"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
|
||||
)
|
||||
)
|
||||
Opcode.RETURN_VOID,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||
import app.revanced.patches.music.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
||||
import app.revanced.patches.music.misc.gms.fingerprints.*
|
||||
import app.revanced.patches.music.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.music.misc.integrations.fingerprints.ApplicationInitFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
||||
|
||||
@@ -21,7 +20,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
CastContextFetchFingerprint,
|
||||
),
|
||||
mainActivityOnCreateFingerprint = ApplicationInitFingerprint,
|
||||
mainActivityOnCreateFingerprint = MusicActivityOnCreateFingerprint,
|
||||
integrationsPatchDependency = IntegrationsPatch::class,
|
||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
||||
compatiblePackages = setOf(CompatiblePackage("com.google.android.apps.youtube.music")),
|
||||
@@ -34,5 +33,5 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
PrimeMethodFingerprint,
|
||||
),
|
||||
) {
|
||||
override val gmsCoreVendor by gmsCoreVendorGroupIdOption
|
||||
override val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.music.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object MusicActivityOnCreateFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroid/os/Bundle;"),
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.type.endsWith("/MusicActivity;")
|
||||
}
|
||||
)
|
||||
@@ -1,26 +1,12 @@
|
||||
package app.revanced.patches.music.premium.backgroundplay
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint
|
||||
|
||||
|
||||
@Patch(
|
||||
name = "Background play",
|
||||
description = "Enables playing music in the background.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object BackgroundPlayPatch : BytecodePatch(setOf(BackgroundPlaybackDisableFingerprint)) {
|
||||
override fun execute(context: BytecodeContext) =
|
||||
BackgroundPlaybackDisableFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0, """
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
"""
|
||||
) ?: throw BackgroundPlaybackDisableFingerprint.exception
|
||||
}
|
||||
import app.revanced.patches.music.layout.minimizedplayback.MinimizedPlaybackPatch
|
||||
@Deprecated("This patch has been merged into MinimizedPlaybackPatch.")
|
||||
object BackgroundPlayPatch : BytecodePatch(
|
||||
dependencies = setOf(MinimizedPlaybackPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package app.revanced.patches.music.premium.backgroundplay.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
|
||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||
internal object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
|
||||
"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
|
||||
)
|
||||
)
|
||||
@@ -2,7 +2,7 @@ package app.revanced.patches.shared.misc.gms
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -12,7 +12,7 @@ import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.AC
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.AUTHORITIES
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.PERMISSIONS
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint.GET_GMS_CORE_VENDOR_METHOD_NAME
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint.GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.returnEarly
|
||||
@@ -32,7 +32,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
* @param toPackageName The package name to fall back to if no custom package name is specified in patch options.
|
||||
* @param primeMethodFingerprint The fingerprint of the "prime" method that needs to be patched.
|
||||
* @param earlyReturnFingerprints The fingerprints of methods that need to be returned early.
|
||||
* @param mainActivityOnCreateFingerprint The fingerprint of the main activity's onCreate method.
|
||||
* @param mainActivityOnCreateFingerprint The fingerprint of the main activity onCreate method.
|
||||
* @param integrationsPatchDependency The patch responsible for the integrations.
|
||||
* @param gmsCoreSupportResourcePatch The corresponding resource patch that is used to patch the resources.
|
||||
* @param dependencies Additional dependencies of this patch.
|
||||
@@ -60,7 +60,10 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
integrationsPatchDependency,
|
||||
) + dependencies,
|
||||
compatiblePackages = compatiblePackages,
|
||||
fingerprints = setOf(GmsCoreSupportFingerprint, mainActivityOnCreateFingerprint) + fingerprints,
|
||||
fingerprints = setOf(
|
||||
GmsCoreSupportFingerprint,
|
||||
mainActivityOnCreateFingerprint,
|
||||
) + fingerprints,
|
||||
requiresIntegrations = true,
|
||||
) {
|
||||
init {
|
||||
@@ -68,7 +71,7 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
gmsCoreSupportResourcePatch.options.values.forEach(options::register)
|
||||
}
|
||||
|
||||
internal abstract val gmsCoreVendor: String?
|
||||
internal abstract val gmsCoreVendorGroupId: String?
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName)
|
||||
@@ -93,16 +96,17 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
// Return these methods early to prevent the app from crashing.
|
||||
earlyReturnFingerprints.toList().returnEarly()
|
||||
|
||||
// Check the availability of GmsCore.
|
||||
mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstruction(
|
||||
1, // Hack to not disturb other patches (such as the integrations patch).
|
||||
"invoke-static {}, Lapp/revanced/integrations/youtube/patches/GmsCoreSupport;->checkAvailability()V",
|
||||
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
|
||||
mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, Lapp/revanced/integrations/shared/GmsCoreSupport;->" +
|
||||
"checkGmsCore(Landroid/app/Activity;)V",
|
||||
) ?: throw mainActivityOnCreateFingerprint.exception
|
||||
|
||||
// Change the vendor of GmsCore in ReVanced Integrations.
|
||||
GmsCoreSupportFingerprint.result?.mutableClass?.methods
|
||||
?.single { it.name == GET_GMS_CORE_VENDOR_METHOD_NAME }
|
||||
?.replaceInstruction(0, "const-string v0, \"$gmsCoreVendor\"")
|
||||
?.single { it.name == GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME }
|
||||
?.replaceInstruction(0, "const-string v0, \"$gmsCoreVendorGroupId\"")
|
||||
?: throw GmsCoreSupportFingerprint.exception
|
||||
}
|
||||
|
||||
@@ -146,10 +150,10 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
in PERMISSIONS,
|
||||
in ACTIONS,
|
||||
in AUTHORITIES,
|
||||
-> referencedString.replace("com.google", gmsCoreVendor!!)
|
||||
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
|
||||
|
||||
// No vendor prefix for whatever reason...
|
||||
"subscribedfeeds" -> "$gmsCoreVendor.subscribedfeeds"
|
||||
"subscribedfeeds" -> "$gmsCoreVendorGroupId.subscribedfeeds"
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -162,7 +166,7 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
if (str.startsWith(uriPrefix)) {
|
||||
return str.replace(
|
||||
uriPrefix,
|
||||
"content://${authority.replace("com.google", gmsCoreVendor!!)}",
|
||||
"content://${authority.replace("com.google", gmsCoreVendorGroupId!!)}",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -170,7 +174,7 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
// gms also has a 'subscribedfeeds' authority, check for that one too
|
||||
val subFeedsUriPrefix = "content://subscribedfeeds"
|
||||
if (str.startsWith(subFeedsUriPrefix)) {
|
||||
return str.replace(subFeedsUriPrefix, "content://$gmsCoreVendor.subscribedfeeds")
|
||||
return str.replace(subFeedsUriPrefix, "content://$gmsCoreVendorGroupId.subscribedfeeds")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,6 @@ abstract class BaseGmsCoreSupportResourcePatch(
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val VANCED_VENDOR = "com.mgoogle"
|
||||
private const val PACKAGE_NAME_REGEX_PATTERN = "^[a-z]\\w*(\\.[a-z]\\w*)+\$"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
internal object GmsCoreSupportFingerprint : MethodFingerprint(
|
||||
customFingerprint = { _, classDef ->
|
||||
classDef.type.endsWith("GmsCoreSupport;")
|
||||
}
|
||||
},
|
||||
) {
|
||||
const val GET_GMS_CORE_VENDOR_METHOD_NAME = "getGmsCoreVendor"
|
||||
const val GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME = "getGmsCoreVendorGroupId"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package app.revanced.patches.shared.misc.hex
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.RawResourcePatch
|
||||
import kotlin.math.max
|
||||
|
||||
abstract class BaseHexPatch : RawResourcePatch() {
|
||||
abstract val replacements: List<Replacement>
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
replacements.groupBy { it.targetFilePath }.forEach { (targetFilePath, replacements) ->
|
||||
val targetFile = try {
|
||||
context[targetFilePath, true]
|
||||
} catch (e: Exception) {
|
||||
throw PatchException("Could not find target file: $targetFilePath")
|
||||
}
|
||||
|
||||
// TODO: Use a file channel to read and write the file instead of reading the whole file into memory,
|
||||
// in order to reduce memory usage.
|
||||
val targetFileBytes = targetFile.readBytes()
|
||||
|
||||
replacements.forEach { replacement ->
|
||||
replacement.replacePattern(targetFileBytes)
|
||||
}
|
||||
|
||||
targetFile.writeBytes(targetFileBytes)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a pattern to search for and its replacement pattern.
|
||||
*
|
||||
* @property pattern The pattern to search for.
|
||||
* @property replacementPattern The pattern to replace the [pattern] with.
|
||||
* @property targetFilePath The path to the file to make the changes in relative to the APK root.
|
||||
*/
|
||||
class Replacement(
|
||||
private val pattern: String,
|
||||
replacementPattern: String,
|
||||
internal val targetFilePath: String,
|
||||
) {
|
||||
private val patternBytes = pattern.toByteArrayPattern()
|
||||
private val replacementPattern = replacementPattern.toByteArrayPattern()
|
||||
|
||||
init {
|
||||
if (this.patternBytes.size != this.replacementPattern.size) {
|
||||
throw PatchException("Pattern and replacement pattern must have the same length: $pattern")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the [patternBytes] with the [replacementPattern] in the [targetFileBytes].
|
||||
*
|
||||
* @param targetFileBytes The bytes of the file to make the changes in.
|
||||
*/
|
||||
fun replacePattern(targetFileBytes: ByteArray) {
|
||||
val startIndex = indexOfPatternIn(targetFileBytes)
|
||||
|
||||
if (startIndex == -1) {
|
||||
throw PatchException("Pattern not found in target file: $pattern")
|
||||
}
|
||||
|
||||
replacementPattern.copyInto(targetFileBytes, startIndex)
|
||||
}
|
||||
|
||||
// TODO: Allow searching in a file channel instead of a byte array to reduce memory usage.
|
||||
/**
|
||||
* Returns the index of the first occurrence of [patternBytes] in the haystack
|
||||
* using the Boyer-Moore algorithm.
|
||||
*
|
||||
* @param haystack The array to search in.
|
||||
*
|
||||
* @return The index of the first occurrence of the [patternBytes] in the haystack or -1
|
||||
* if the [patternBytes] is not found.
|
||||
*/
|
||||
private fun indexOfPatternIn(haystack: ByteArray): Int {
|
||||
val needle = patternBytes
|
||||
|
||||
val haystackLength = haystack.size - 1
|
||||
val needleLength = needle.size - 1
|
||||
val right = IntArray(256) { -1 }
|
||||
|
||||
for (i in 0 until needleLength) right[needle[i].toInt().and(0xFF)] = i
|
||||
|
||||
var skip: Int
|
||||
for (i in 0..haystackLength - needleLength) {
|
||||
skip = 0
|
||||
|
||||
for (j in needleLength - 1 downTo 0)
|
||||
if (needle[j] != haystack[i + j]) {
|
||||
skip = max(1, j - right[haystack[i + j].toInt().and(0xFF)])
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if (skip == 0) return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Convert a string representing a pattern of hexadecimal bytes to a byte array.
|
||||
*
|
||||
* @return The byte array representing the pattern.
|
||||
* @throws PatchException If the pattern is invalid.
|
||||
*/
|
||||
private fun String.toByteArrayPattern() = try {
|
||||
split(" ").map { it.toInt(16).toByte() }.toByteArray()
|
||||
} catch (e: NumberFormatException) {
|
||||
throw PatchException(
|
||||
"Could not parse pattern: $this. A pattern is a sequence of case insensitive strings " +
|
||||
"representing hexadecimal bytes separated by spaces",
|
||||
e,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,21 @@ package app.revanced.patches.shared.misc.integrations
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
|
||||
import app.revanced.patches.shared.misc.integrations.fingerprints.ReVancedUtilsPatchesVersionFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import java.util.jar.JarFile
|
||||
|
||||
abstract class BaseIntegrationsPatch(
|
||||
private val hooks: Set<IntegrationsFingerprint>,
|
||||
) : BytecodePatch(hooks) {
|
||||
) : BytecodePatch(hooks + setOf(ReVancedUtilsPatchesVersionFingerprint)) {
|
||||
|
||||
@Deprecated(
|
||||
"Use the constructor without the integrationsDescriptor parameter",
|
||||
@@ -34,6 +38,46 @@ abstract class BaseIntegrationsPatch(
|
||||
hooks.forEach { hook ->
|
||||
hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
|
||||
// Modify Utils method to include the patches release version version.
|
||||
ReVancedUtilsPatchesVersionFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val manifestValue = getPatchesManifestEntry("Version")
|
||||
|
||||
addInstructions(
|
||||
0,
|
||||
"""
|
||||
const-string v0, "$manifestValue"
|
||||
return-object v0
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The value for the manifest entry,
|
||||
* or "Unknown" if the entry does not exist or is blank.
|
||||
*/
|
||||
@Suppress("SameParameterValue")
|
||||
private fun getPatchesManifestEntry(attributeKey: String) = JarFile(getCurrentJarFilePath()).use { jarFile ->
|
||||
jarFile.manifest.mainAttributes.entries.firstOrNull { it.key.toString() == attributeKey }?.value?.toString()
|
||||
?: "Unknown"
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The file path for the jar this classfile is contained inside.
|
||||
*/
|
||||
private fun getCurrentJarFilePath(): String {
|
||||
val className = object {}::class.java.enclosingClass.name.replace('.', '/') + ".class"
|
||||
val classUrl = object {}::class.java.classLoader.getResource(className)
|
||||
if (classUrl != null) {
|
||||
val urlString = classUrl.toString()
|
||||
|
||||
if (urlString.startsWith("jar:file:")) {
|
||||
val end = urlString.indexOf('!')
|
||||
return urlString.substring("jar:file:".length, end)
|
||||
}
|
||||
}
|
||||
throw IllegalStateException("Not running from inside a JAR file.")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,7 +94,7 @@ abstract class BaseIntegrationsPatch(
|
||||
strings: Iterable<String>? = null,
|
||||
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
|
||||
private val insertIndexResolver: ((Method) -> Int) = object : IHookInsertIndexResolver {},
|
||||
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}
|
||||
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {},
|
||||
) : MethodFingerprint(
|
||||
returnType,
|
||||
accessFlags,
|
||||
@@ -59,9 +103,11 @@ abstract class BaseIntegrationsPatch(
|
||||
strings,
|
||||
customFingerprint,
|
||||
) {
|
||||
@Deprecated("Previous constructor that is missing the insert index." +
|
||||
@Deprecated(
|
||||
"Previous constructor that is missing the insert index." +
|
||||
"Here only for binary compatibility, " +
|
||||
"and this can be removed after the next major version update.")
|
||||
"and this can be removed after the next major version update.",
|
||||
)
|
||||
constructor(
|
||||
returnType: String? = null,
|
||||
accessFlags: Int? = null,
|
||||
@@ -69,7 +115,7 @@ abstract class BaseIntegrationsPatch(
|
||||
opcodes: Iterable<Opcode?>? = null,
|
||||
strings: Iterable<String>? = null,
|
||||
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
|
||||
contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}
|
||||
contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {},
|
||||
) : this(
|
||||
returnType,
|
||||
accessFlags,
|
||||
@@ -78,7 +124,7 @@ abstract class BaseIntegrationsPatch(
|
||||
strings,
|
||||
customFingerprint,
|
||||
object : IHookInsertIndexResolver {},
|
||||
contextRegisterResolver
|
||||
contextRegisterResolver,
|
||||
)
|
||||
|
||||
fun invoke(integrationsDescriptor: String) {
|
||||
@@ -103,7 +149,7 @@ abstract class BaseIntegrationsPatch(
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/shared/Utils;"
|
||||
internal companion object {
|
||||
internal const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/shared/Utils;"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.shared.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object ReVancedUtilsPatchesVersionFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
returnType = "Ljava/lang/String;",
|
||||
parameters = listOf(),
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "getPatchesReleaseVersion" &&
|
||||
classDef.type == BaseIntegrationsPatch.INTEGRATIONS_CLASS_DESCRIPTOR
|
||||
}
|
||||
)
|
||||
@@ -8,19 +8,15 @@ import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object ResourceMappingPatch : ResourcePatch() {
|
||||
internal lateinit var resourceMappings: List<ResourceElement>
|
||||
private set
|
||||
private val resourceMappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
|
||||
|
||||
private val THREAD_COUNT = Runtime.getRuntime().availableProcessors()
|
||||
private val threadPoolExecutor = Executors.newFixedThreadPool(THREAD_COUNT)
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
// save the file in memory to concurrently read from
|
||||
// sSve the file in memory to concurrently read from it.
|
||||
val resourceXmlFile = context.get("res/values/public.xml").readBytes()
|
||||
|
||||
// create a synchronized list to store the resource mappings
|
||||
val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
|
||||
|
||||
for (threadIndex in 0 until THREAD_COUNT) {
|
||||
threadPoolExecutor.execute thread@{
|
||||
context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
|
||||
@@ -33,7 +29,7 @@ object ResourceMappingPatch : ResourcePatch() {
|
||||
val batchStart = jobSize * threadIndex
|
||||
val batchEnd = jobSize * (threadIndex + 1)
|
||||
element@ for (i in batchStart until batchEnd) {
|
||||
// make sure to not go out of bounds when rounding errors occur at calculating the jobSize
|
||||
// Prevent out of bounds.
|
||||
if (i >= resourcesLength) return@thread
|
||||
|
||||
val node = resources.item(i)
|
||||
@@ -46,18 +42,18 @@ object ResourceMappingPatch : ResourcePatch() {
|
||||
|
||||
val id = node.getAttribute("id").substring(2).toLong(16)
|
||||
|
||||
mappings.add(ResourceElement(typeAttribute, nameAttribute, id))
|
||||
resourceMappings.add(ResourceElement(typeAttribute, nameAttribute, id))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
threadPoolExecutor
|
||||
.also { it.shutdown() }
|
||||
.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
|
||||
|
||||
resourceMappings = mappings
|
||||
threadPoolExecutor.also { it.shutdown() }.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
operator fun get(type: String, name: String) = resourceMappings.first {
|
||||
it.type == type && it.name == name
|
||||
}.id
|
||||
|
||||
data class ResourceElement(val type: String, val name: String, val id: Long)
|
||||
}
|
||||
|
||||
@@ -16,10 +16,19 @@ import org.w3c.dom.Document
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class NonInteractivePreference(
|
||||
key: String,
|
||||
titleKey: String = "${key}_title",
|
||||
summaryKey: String? = "${key}_summary",
|
||||
tag: String = "Preference",
|
||||
val selectable: Boolean = false
|
||||
) : BasePreference(null, "${key}_title", summaryKey, tag) {
|
||||
) : BasePreference(key, titleKey, summaryKey, tag) {
|
||||
|
||||
@Deprecated("Here only for binary compatibility, and should be removed after the next major version update.")
|
||||
constructor(
|
||||
key: String,
|
||||
summaryKey: String? = "${key}_summary",
|
||||
tag: String = "Preference",
|
||||
selectable: Boolean = false
|
||||
) : this(key, "${key}_title", summaryKey, tag, selectable)
|
||||
|
||||
override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) =
|
||||
super.serialize(ownerDocument, resourceCallback).apply {
|
||||
|
||||
@@ -11,12 +11,11 @@ object PremiumNavbarTabResourcePatch : ResourcePatch() {
|
||||
internal var premiumTabId = -1L
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
premiumTabId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "id" && it.name == "premium_tab"
|
||||
}.id
|
||||
premiumTabId = ResourceMappingPatch["id", "premium_tab"]
|
||||
|
||||
showBottomNavigationItemsTextId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "bool" && it.name == "show_bottom_navigation_items_text"
|
||||
}.id
|
||||
showBottomNavigationItemsTextId = ResourceMappingPatch[
|
||||
"bool",
|
||||
"show_bottom_navigation_items_text",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
package app.revanced.patches.strava.subscription
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.strava.subscription.fingerprints.GetSubscribedFingerprint
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Unlock subscription features",
|
||||
description = "Unlocks \"Routes\", \"Matched Runs\" and \"Segment Efforts\".",
|
||||
compatiblePackages = [CompatiblePackage("com.strava", ["320.12"])]
|
||||
compatiblePackages = [CompatiblePackage("com.strava")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object UnlockSubscriptionPatch : BytecodePatch(setOf(GetSubscribedFingerprint)) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package app.revanced.patches.tumblr.annoyances.popups.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
// This method is responsible for loading and displaying the visual Layout of the Gift Message Popup.
|
||||
internal object ShowGiftMessagePopupFingerprint : MethodFingerprint(
|
||||
strings = listOf("activity", "anchorView"),
|
||||
customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("GiftMessagePopup;") }
|
||||
strings = listOf("activity", "anchorView", "textMessage"),
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.FINAL or AccessFlags.PUBLIC
|
||||
)
|
||||
@@ -28,6 +28,9 @@ object OverrideFeatureFlagsPatch : BytecodePatch(
|
||||
internal lateinit var addOverride: (name: String, value: String) -> Unit private set
|
||||
|
||||
override fun execute(context: BytecodeContext) = GetFeatureValueFingerprint.result?.let {
|
||||
val configurationClass = it.method.definingClass
|
||||
val featureClass = it.method.parameterTypes[0].toString()
|
||||
|
||||
// The method we want to inject into does not have enough registers, so we inject a helper method
|
||||
// and inject more instructions into it later, see addOverride.
|
||||
// This is not in an integration since the unused variable would get compiled away and the method would
|
||||
@@ -35,7 +38,7 @@ object OverrideFeatureFlagsPatch : BytecodePatch(
|
||||
val helperMethod = ImmutableMethod(
|
||||
it.method.definingClass,
|
||||
"getValueOverride",
|
||||
listOf(ImmutableMethodParameter("Lcom/tumblr/configuration/Feature;", null, "feature")),
|
||||
listOf(ImmutableMethodParameter(featureClass, null, "feature")),
|
||||
"Ljava/lang/String;",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
null,
|
||||
@@ -50,7 +53,7 @@ object OverrideFeatureFlagsPatch : BytecodePatch(
|
||||
0,
|
||||
"""
|
||||
# toString() the enum value
|
||||
invoke-virtual {p1}, Lcom/tumblr/configuration/Feature;->toString()Ljava/lang/String;
|
||||
invoke-virtual {p1}, $featureClass->toString()Ljava/lang/String;
|
||||
move-result-object v0
|
||||
|
||||
# !!! If you add more instructions above this line, update helperInsertIndex below!
|
||||
@@ -75,7 +78,7 @@ object OverrideFeatureFlagsPatch : BytecodePatch(
|
||||
getFeatureIndex,
|
||||
"""
|
||||
# Call the Helper Method with the Feature
|
||||
invoke-virtual {p0, p1}, Lcom/tumblr/configuration/Configuration;->getValueOverride(Lcom/tumblr/configuration/Feature;)Ljava/lang/String;
|
||||
invoke-virtual {p0, p1}, $configurationClass->getValueOverride($featureClass)Ljava/lang/String;
|
||||
move-result-object v0
|
||||
# If it returned null, skip
|
||||
if-eqz v0, :is_null
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package app.revanced.patches.tumblr.featureflags.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
// This fingerprint targets the method to get the value of a Feature in the class "com.tumblr.configuration.Feature".
|
||||
@@ -19,5 +21,7 @@ internal object GetFeatureValueFingerprint : MethodFingerprint(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT
|
||||
),
|
||||
customFingerprint = { method, _ -> method.definingClass == "Lcom/tumblr/configuration/Configuration;" }
|
||||
returnType = "Ljava/lang/String;",
|
||||
parameters = listOf("L", "Z"),
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL
|
||||
)
|
||||
@@ -0,0 +1,67 @@
|
||||
package app.revanced.patches.tumblr.fixes
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.tumblr.fixes.fingerprints.AddQueryParamFingerprint
|
||||
import app.revanced.patches.tumblr.fixes.fingerprints.HttpPathParserFingerprint
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Fix old versions",
|
||||
description = "Fixes old versions of the app (v33.2 and earlier) breaking due to Tumblr removing remnants of Tumblr" +
|
||||
" Live from the API, which causes many requests to fail. This patch has no effect on newer versions of the app.",
|
||||
compatiblePackages = [CompatiblePackage("com.tumblr")],
|
||||
use = false,
|
||||
)
|
||||
@Suppress("unused")
|
||||
object FixOldVersionsPatch : BytecodePatch(
|
||||
setOf(HttpPathParserFingerprint, AddQueryParamFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val liveQueryParameters = listOf(
|
||||
",?live_now",
|
||||
",?live_streaming_user_id",
|
||||
)
|
||||
|
||||
HttpPathParserFingerprint.result?.let {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
// Remove the live query parameters from the path when it's specified via a @METHOD annotation.
|
||||
for (liveQueryParameter in liveQueryParameters) {
|
||||
it.mutableMethod.addInstructions(
|
||||
endIndex + 1,
|
||||
"""
|
||||
# urlPath = urlPath.replace(liveQueryParameter, "")
|
||||
const-string p1, "$liveQueryParameter"
|
||||
const-string p3, ""
|
||||
invoke-virtual {p2, p1, p3}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
|
||||
move-result-object p2
|
||||
""",
|
||||
)
|
||||
}
|
||||
} ?: throw HttpPathParserFingerprint.exception
|
||||
|
||||
AddQueryParamFingerprint.result?.let {
|
||||
// Remove the live query parameters when passed via a parameter which has the @Query annotation.
|
||||
// e.g. an API call could be defined like this:
|
||||
// @GET("api/me/info")
|
||||
// ApiResponse getCurrentUserInfo(@Query("fields[blog]") String value)
|
||||
// which would result in the path "api/me/inf0?fields[blog]=${value}"
|
||||
// Here we make sure that this value doesn't contain the broken query parameters.
|
||||
for (liveQueryParameter in liveQueryParameters) {
|
||||
it.mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
# queryParameterValue = queryParameterValue.replace(liveQueryParameter, "")
|
||||
const-string v0, "$liveQueryParameter"
|
||||
const-string v1, ""
|
||||
invoke-virtual {p2, v0, v1}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
|
||||
move-result-object p2
|
||||
""",
|
||||
)
|
||||
}
|
||||
} ?: throw AddQueryParamFingerprint.exception
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.tumblr.fixes.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
// Fingerprint for the addQueryParam method from retrofit2
|
||||
// https://github.com/square/retrofit/blob/trunk/retrofit/src/main/java/retrofit2/RequestBuilder.java#L186
|
||||
// Injecting here allows modifying dynamically set query parameters
|
||||
internal object AddQueryParamFingerprint : MethodFingerprint(
|
||||
strings = listOf("Malformed URL. Base: ", ", Relative: "),
|
||||
parameters = listOf("Ljava/lang/String;", "Ljava/lang/String;", "Z"),
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.tumblr.fixes.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
// Fingerprint for the parseHttpMethodAndPath method from retrofit2
|
||||
// https://github.com/square/retrofit/blob/ebf87b10997e2136af4d335276fa950221852c64/retrofit/src/main/java/retrofit2/RequestFactory.java#L270-L302
|
||||
// Injecting here allows modifying the path/query params of API endpoints defined via annotations
|
||||
internal object HttpPathParserFingerprint : MethodFingerprint(
|
||||
strings = listOf("Only one HTTP method is allowed. Found: %s and %s."),
|
||||
opcodes = listOf(
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
),
|
||||
)
|
||||
@@ -8,11 +8,11 @@ import app.revanced.patches.tumblr.featureflags.OverrideFeatureFlagsPatch
|
||||
import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch
|
||||
|
||||
@Patch(
|
||||
name = "Disable Tumblr Live",
|
||||
description = "Disable the Tumblr Live tab button and dashboard carousel.",
|
||||
dependencies = [OverrideFeatureFlagsPatch::class, TimelineFilterPatch::class],
|
||||
compatiblePackages = [CompatiblePackage("com.tumblr")],
|
||||
)
|
||||
@Deprecated("Tumblr Live was removed and is no longer served in the feed, making this patch useless.")
|
||||
@Suppress("unused")
|
||||
object DisableTumblrLivePatch : BytecodePatch(emptySet()) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
@@ -62,7 +62,17 @@ object SettingsPatch : BytecodePatch(
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
PreferenceScreen.MISC.OTHER.addPreferences(
|
||||
SwitchPreference("revanced_debug")
|
||||
// The debug setting is shared across multiple apps and the key must be the same.
|
||||
// But the title and summary must be different, otherwise when the strings file is flattened
|
||||
// for Crowdin push, Crowdin gets confused by the duplicate keys.
|
||||
// FIXME: Ideally the shared debug strings are extracted into a common app group
|
||||
// and then both apps import that. But for now unique unique title and summary keys also works.
|
||||
SwitchPreference(
|
||||
key = "revanced_debug",
|
||||
titleKey = "revanced_twitch_debug_title",
|
||||
summaryOnKey = "revanced_twitch_debug_summary_on",
|
||||
summaryOffKey = "revanced_twitch_debug_summary_off"
|
||||
)
|
||||
)
|
||||
|
||||
// Hook onCreate to handle fragment creation
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.twitter.misc.links.fingerprints.SanitizeSharingLinksFingerprint
|
||||
import app.revanced.util.exception
|
||||
|
||||
@Patch(
|
||||
name = "Sanitize sharing links",
|
||||
description = "Removes the tracking query parameters from links before they are shared.",
|
||||
compatiblePackages = [CompatiblePackage("com.twitter.android")],
|
||||
)
|
||||
object SanitizeSharingLinksPatch : BytecodePatch(
|
||||
setOf(SanitizeSharingLinksFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
SanitizeSharingLinksFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
# Method takes in a link (string, param 0) and then appends the tracking query params,
|
||||
# so all we need to do is return back the passed-in string
|
||||
return-object p0
|
||||
""",
|
||||
) ?: throw SanitizeSharingLinksFingerprint.exception
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package app.revanced.patches.twitter.misc.links.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object SanitizeSharingLinksFingerprint : MethodFingerprint(
|
||||
strings = listOf("<this>", "shareParam", "sessionToken"),
|
||||
returnType = "Ljava/lang/String;",
|
||||
)
|
||||
@@ -42,7 +42,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -14,8 +14,8 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
LithoFilterPatch::class,
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
]
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
object HideAdsResourcePatch : ResourcePatch() {
|
||||
private const val FILTER_CLASS_DESCRIPTOR =
|
||||
@@ -30,16 +30,16 @@ object HideAdsResourcePatch : ResourcePatch() {
|
||||
SwitchPreference("revanced_hide_general_ads"),
|
||||
SwitchPreference("revanced_hide_fullscreen_ads"),
|
||||
SwitchPreference("revanced_hide_buttoned_ads"),
|
||||
SwitchPreference("revanced_hide_paid_content_ads"),
|
||||
SwitchPreference("revanced_hide_paid_promotion_label"),
|
||||
SwitchPreference("revanced_hide_self_sponsor_ads"),
|
||||
SwitchPreference("revanced_hide_products_banner"),
|
||||
SwitchPreference("revanced_hide_shopping_links"),
|
||||
SwitchPreference("revanced_hide_web_search_results"),
|
||||
SwitchPreference("revanced_hide_merchandise_banners")
|
||||
SwitchPreference("revanced_hide_merchandise_banners"),
|
||||
)
|
||||
|
||||
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
||||
|
||||
adAttributionId = ResourceMappingPatch.resourceMappings.single { it.name == "ad_attribution" }.id
|
||||
adAttributionId = ResourceMappingPatch["id", "ad_attribution"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -41,7 +41,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -29,7 +29,9 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -38,7 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -14,7 +14,7 @@ import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
name = "Downloads",
|
||||
description = "Adds support to download videos with an external downloader app" +
|
||||
description = "Adds support to download videos with an external downloader app " +
|
||||
"using the in-app download button or a video player action button.",
|
||||
dependencies = [
|
||||
DownloadsResourcePatch::class,
|
||||
@@ -35,7 +35,9 @@ import app.revanced.util.resultOrThrow
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -38,7 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -40,7 +40,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -36,7 +36,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
],
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
SwipeControlsResourcePatch::class
|
||||
SwipeControlsResourcePatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
@@ -42,17 +42,22 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
]
|
||||
)
|
||||
]
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43", // 19.12.x has an issue with opening YT using external links,
|
||||
// and the app then crashes if double tap to skip forward/back is immediately used.
|
||||
// The stack trace shows a call coming from integrations SwipeController,
|
||||
// but it may be a bug in YT itself as other target versions do not have this issue.
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object SwipeControlsBytecodePatch : BytecodePatch(
|
||||
setOf(
|
||||
MainActivityFingerprint,
|
||||
SwipeControlsHostActivityFingerprint
|
||||
)
|
||||
SwipeControlsHostActivityFingerprint,
|
||||
),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
val wrapperClass = SwipeControlsHostActivityFingerprint.result!!.mutableClass
|
||||
@@ -74,9 +79,9 @@ object SwipeControlsBytecodePatch : BytecodePatch(
|
||||
accessFlags and AccessFlags.FINAL.value.inv(),
|
||||
annotations,
|
||||
hiddenApiRestrictions,
|
||||
implementation
|
||||
implementation,
|
||||
).toMutable()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ internal object SwipeControlsResourcePatch : ResourcePatch() {
|
||||
SwitchPreference("revanced_swipe_press_to_engage"),
|
||||
SwitchPreference("revanced_swipe_haptic_feedback"),
|
||||
SwitchPreference("revanced_swipe_save_and_restore_brightness"),
|
||||
SwitchPreference("revanced_swipe_lowest_value_enable_auto_brightness"),
|
||||
TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER),
|
||||
TextPreference("revanced_swipe_text_overlay_size", inputType = InputType.NUMBER),
|
||||
TextPreference("revanced_swipe_overlay_background_alpha", inputType = InputType.NUMBER),
|
||||
|
||||
@@ -40,7 +40,9 @@ import app.revanced.util.exception
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
],
|
||||
|
||||
@@ -39,7 +39,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -63,8 +65,7 @@ object HideButtonsPatch : ResourcePatch() {
|
||||
SwitchPreference("revanced_hide_download_button"),
|
||||
SwitchPreference("revanced_hide_thanks_button"),
|
||||
SwitchPreference("revanced_hide_clip_button"),
|
||||
SwitchPreference("revanced_hide_playlist_button"),
|
||||
SwitchPreference("revanced_hide_shop_button")
|
||||
SwitchPreference("revanced_hide_playlist_button")
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.shared.fingerprints.LayoutConstructorFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.findIndexForIdResource
|
||||
import app.revanced.util.indexOfIdResourceOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
@@ -27,7 +27,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
@@ -49,27 +49,29 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
]
|
||||
)
|
||||
]
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43",
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object HideAutoplayButtonPatch : BytecodePatch(
|
||||
setOf(LayoutConstructorFingerprint)
|
||||
setOf(LayoutConstructorFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||
SwitchPreference("revanced_hide_autoplay_button")
|
||||
SwitchPreference("revanced_hide_autoplay_button"),
|
||||
)
|
||||
|
||||
LayoutConstructorFingerprint.result?.mutableMethod?.apply {
|
||||
val layoutGenMethodInstructions = implementation!!.instructions
|
||||
|
||||
// resolve the offsets of where to insert the branch instructions and ...
|
||||
val insertIndex = findIndexForIdResource("autonav_preview_stub")
|
||||
val insertIndex = indexOfIdResourceOrThrow("autonav_preview_stub")
|
||||
|
||||
// where to branch away
|
||||
val branchIndex =
|
||||
@@ -90,8 +92,8 @@ object HideAutoplayButtonPatch : BytecodePatch(
|
||||
move-result v$clobberRegister
|
||||
if-eqz v$clobberRegister, :hidden
|
||||
""",
|
||||
ExternalLabel("hidden", jumpInstruction)
|
||||
ExternalLabel("hidden", jumpInstruction),
|
||||
)
|
||||
} ?: throw LayoutConstructorFingerprint.exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ import com.android.tools.smali.dexlib2.Opcode
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -10,10 +10,10 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.*
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.injectHook
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.ANDROID_AUTOMOTIVE_STRING
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.AddCreateButtonViewFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@@ -24,8 +24,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
ResolvePivotBarFingerprintsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
NavigationBarHookPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
@@ -47,7 +47,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
],
|
||||
),
|
||||
],
|
||||
@@ -76,53 +78,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||
),
|
||||
)
|
||||
|
||||
/*
|
||||
* Resolve fingerprints
|
||||
*/
|
||||
|
||||
val initializeButtonsResult = InitializeButtonsFingerprint.result!!
|
||||
|
||||
val fingerprintResults =
|
||||
arrayOf(PivotBarEnumFingerprint, PivotBarButtonsViewFingerprint)
|
||||
.onEach {
|
||||
if (!it.resolve(
|
||||
context,
|
||||
initializeButtonsResult.mutableMethod,
|
||||
initializeButtonsResult.mutableClass,
|
||||
)
|
||||
) {
|
||||
throw it.exception
|
||||
}
|
||||
}
|
||||
.map { it.result!!.scanResult.patternScanResult!! }
|
||||
|
||||
val enumScanResult = fingerprintResults[0]
|
||||
val buttonViewResult = fingerprintResults[1]
|
||||
|
||||
val enumHookInsertIndex = enumScanResult.startIndex + 2
|
||||
val buttonHookInsertIndex = buttonViewResult.endIndex
|
||||
|
||||
/*
|
||||
* Inject hooks
|
||||
*/
|
||||
|
||||
val enumHook = "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->lastNavigationButton:Ljava/lang/Enum;"
|
||||
val buttonHook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideButton(Landroid/view/View;)V"
|
||||
|
||||
// Inject bottom to top to not mess up the indices
|
||||
mapOf(
|
||||
buttonHook to buttonHookInsertIndex,
|
||||
enumHook to enumHookInsertIndex,
|
||||
).forEach { (hook, insertIndex) ->
|
||||
initializeButtonsResult.mutableMethod.injectHook(hook, insertIndex)
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide create or switch it with notifications buttons.
|
||||
*/
|
||||
|
||||
// Switch create with notifications button.
|
||||
AddCreateButtonViewFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val stringIndex = it.scanResult.stringsScanResult!!.matches.find { match ->
|
||||
@@ -130,7 +86,8 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||
}!!.index
|
||||
|
||||
val conditionalCheckIndex = stringIndex - 1
|
||||
val conditionRegister = getInstruction<OneRegisterInstruction>(conditionalCheckIndex).registerA
|
||||
val conditionRegister =
|
||||
getInstruction<OneRegisterInstruction>(conditionalCheckIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
conditionalCheckIndex,
|
||||
@@ -142,26 +99,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||
}
|
||||
} ?: throw AddCreateButtonViewFingerprint.exception
|
||||
|
||||
/*
|
||||
* Resolve fingerprints
|
||||
*/
|
||||
|
||||
InitializeButtonsFingerprint.result!!.let {
|
||||
if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass)) {
|
||||
throw PivotBarCreateButtonViewFingerprint.exception
|
||||
}
|
||||
}
|
||||
|
||||
PivotBarCreateButtonViewFingerprint.result!!.apply {
|
||||
val insertIndex = scanResult.patternScanResult!!.endIndex
|
||||
|
||||
/*
|
||||
* Inject hooks
|
||||
*/
|
||||
val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V"
|
||||
|
||||
mutableMethod.injectHook(hook, insertIndex)
|
||||
}
|
||||
// Hook navigation button created, in order to hide them.
|
||||
NavigationBarHookPatch.hookNavigationButtonCreated(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.navigation
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.InitializeButtonsFingerprint
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.PivotBarConstructorFingerprint
|
||||
|
||||
@Patch(
|
||||
description = "Resolves necessary fingerprints.",
|
||||
dependencies = [ResourceMappingPatch::class]
|
||||
)
|
||||
internal object ResolvePivotBarFingerprintsPatch : BytecodePatch(
|
||||
setOf(PivotBarConstructorFingerprint)
|
||||
) {
|
||||
internal var imageOnlyTabResourceId: Long = -1
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
// imageOnlyTabResourceId is used in InitializeButtonsFingerprint fingerprint
|
||||
ResourceMappingPatch.resourceMappings.find { it.type == "layout" && it.name == "image_only_tab" }
|
||||
?.let { imageOnlyTabResourceId = it.id } ?: throw PatchException("Failed to find resource")
|
||||
|
||||
PivotBarConstructorFingerprint.result?.let {
|
||||
// Resolve InitializeButtonsFingerprint on the class of the method
|
||||
// which PivotBarConstructorFingerprint resolved to
|
||||
if (!InitializeButtonsFingerprint.resolve(
|
||||
context,
|
||||
it.classDef
|
||||
)
|
||||
) throw InitializeButtonsFingerprint.exception
|
||||
} ?: throw PivotBarConstructorFingerprint.exception
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PivotBarButtonsViewFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL_RANGE,
|
||||
Opcode.MOVE_RESULT_OBJECT, // target reference
|
||||
Opcode.GOTO,
|
||||
)
|
||||
)
|
||||
@@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PivotBarCreateButtonViewFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_DIRECT_RANGE,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC
|
||||
)
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.navigation.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PivotBarEnumFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_NEZ, // target reference
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
)
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.buttons.navigation.utils
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import com.android.tools.smali.dexlib2.Opcode.MOVE_RESULT_OBJECT
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
internal object InjectionUtils {
|
||||
const val REGISTER_TEMPLATE_REPLACEMENT: String = "REGISTER_INDEX"
|
||||
|
||||
/**
|
||||
* Injects an instruction into insertIndex of the hook.
|
||||
* @param hook The hook to insert.
|
||||
* @param insertIndex The index to insert the instruction at.
|
||||
* [MOVE_RESULT_OBJECT] has to be the previous instruction before [insertIndex].
|
||||
*/
|
||||
fun MutableMethod.injectHook(hook: String, insertIndex: Int) {
|
||||
val injectTarget = this
|
||||
|
||||
// Register to pass to the hook
|
||||
val registerIndex = insertIndex - 1 // MOVE_RESULT_OBJECT is always the previous instruction
|
||||
val register = injectTarget.getInstruction<OneRegisterInstruction>(registerIndex).registerA
|
||||
|
||||
injectTarget.addInstruction(
|
||||
insertIndex,
|
||||
hook.replace("REGISTER_INDEX", register.toString()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -38,7 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
internal object AlbumCardsResourcePatch : ResourcePatch() {
|
||||
@@ -22,11 +22,9 @@ internal object AlbumCardsResourcePatch : ResourcePatch() {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||
SwitchPreference("revanced_hide_album_cards")
|
||||
SwitchPreference("revanced_hide_album_cards"),
|
||||
)
|
||||
|
||||
albumCardId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "layout" && it.name == "album_card"
|
||||
}.id
|
||||
albumCardId = ResourceMappingPatch["layout", "album_card"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.hide.breakingnews
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.youtube.layout.hide.breakingnews.fingerprints.BreakingNewsFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import app.revanced.patches.youtube.layout.hide.general.HideLayoutComponentsPatch
|
||||
|
||||
@Patch(
|
||||
name = "Hide breaking news shelf",
|
||||
description = "Adds an option to hide the breaking news shelf on the homepage tab.",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
BreakingNewsResourcePatch::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"18.32.39",
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
@Deprecated("This patch has been merged to HideLayoutComponentsPatch.")
|
||||
object BreakingNewsPatch : BytecodePatch(
|
||||
setOf(BreakingNewsFingerprint)
|
||||
dependencies = setOf(HideLayoutComponentsPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
BreakingNewsFingerprint.result?.let {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1
|
||||
val moveResultIndex = insertIndex - 1
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val breakingNewsViewRegister =
|
||||
getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"""
|
||||
invoke-static {v$breakingNewsViewRegister},
|
||||
Lapp/revanced/integrations/youtube/patches/HideBreakingNewsPatch;
|
||||
->
|
||||
hideBreakingNews(Landroid/view/View;)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
} ?: throw BreakingNewsFingerprint.exception
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.hide.breakingnews
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
],
|
||||
)
|
||||
internal object BreakingNewsResourcePatch : ResourcePatch() {
|
||||
internal var horizontalCardListId: Long = -1
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||
SwitchPreference("revanced_hide_breaking_news")
|
||||
)
|
||||
|
||||
horizontalCardListId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "layout" && it.name == "horizontal_card_list"
|
||||
}.id
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.hide.breakingnews.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.hide.breakingnews.BreakingNewsResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object BreakingNewsFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
opcodes = listOf(
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IPUT_OBJECT,
|
||||
),
|
||||
literalSupplier = { BreakingNewsResourcePatch.horizontalCardListId }
|
||||
)
|
||||
@@ -38,7 +38,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
@@ -55,9 +57,11 @@ object CommentsPatch : ResourcePatch() {
|
||||
PreferenceScreen(
|
||||
"revanced_comments_screen",
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_preview_comment"),
|
||||
SwitchPreference("revanced_hide_comments_section"),
|
||||
SwitchPreference("revanced_hide_preview_comment")
|
||||
)
|
||||
SwitchPreference("revanced_hide_comment_timestamp_and_emoji_buttons")
|
||||
),
|
||||
sorting = PreferenceScreen.Sorting.UNSORTED
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
internal object CrowdfundingBoxResourcePatch : ResourcePatch() {
|
||||
@@ -22,11 +22,12 @@ internal object CrowdfundingBoxResourcePatch : ResourcePatch() {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||
SwitchPreference("revanced_hide_crowdfunding_box")
|
||||
SwitchPreference("revanced_hide_crowdfunding_box"),
|
||||
)
|
||||
|
||||
crowdfundingBoxId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "layout" && it.name == "donation_companion"
|
||||
}.id
|
||||
crowdfundingBoxId = ResourceMappingPatch[
|
||||
"layout",
|
||||
"donation_companion",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
internal object HideEndscreenCardsResourcePatch : ResourcePatch() {
|
||||
@@ -24,15 +24,13 @@ internal object HideEndscreenCardsResourcePatch : ResourcePatch() {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||
SwitchPreference("revanced_hide_endscreen_cards")
|
||||
SwitchPreference("revanced_hide_endscreen_cards"),
|
||||
)
|
||||
|
||||
fun findEndscreenResourceId(name: String) = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "layout" && it.name == "endscreen_element_layout_$name"
|
||||
}.id
|
||||
fun idOf(name: String) = ResourceMappingPatch["layout", "endscreen_element_layout_$name"]
|
||||
|
||||
layoutCircle = findEndscreenResourceId("circle")
|
||||
layoutIcon = findEndscreenResourceId("icon")
|
||||
layoutVideo = findEndscreenResourceId("video")
|
||||
layoutCircle = idOf("circle")
|
||||
layoutIcon = idOf("icon")
|
||||
layoutVideo = idOf("video")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -25,15 +25,12 @@ internal object HideFilterBarResourcePatch : ResourcePatch() {
|
||||
SwitchPreference("revanced_hide_filter_bar_feed_in_feed"),
|
||||
SwitchPreference("revanced_hide_filter_bar_feed_in_search"),
|
||||
SwitchPreference("revanced_hide_filter_bar_feed_in_related_videos"),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
relatedChipCloudMarginId = "related_chip_cloud_reduced_margins".layoutResourceId("layout")
|
||||
filterBarHeightId = "filter_bar_height".layoutResourceId()
|
||||
barContainerHeightId = "bar_container_height".layoutResourceId()
|
||||
relatedChipCloudMarginId = ResourceMappingPatch["layout", "related_chip_cloud_reduced_margins"]
|
||||
filterBarHeightId = ResourceMappingPatch["dimen", "filter_bar_height"]
|
||||
barContainerHeightId = ResourceMappingPatch["dimen", "bar_container_height"]
|
||||
}
|
||||
|
||||
private fun String.layoutResourceId(type: String = "dimen") =
|
||||
ResourceMappingPatch.resourceMappings.single { it.type == type && it.name == this }.id
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package app.revanced.patches.youtube.layout.hide.floatingmicrophone
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
@@ -13,8 +12,8 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
]
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
internal object HideFloatingMicrophoneButtonResourcePatch : ResourcePatch() {
|
||||
internal var fabButtonId: Long = -1
|
||||
@@ -23,10 +22,9 @@ internal object HideFloatingMicrophoneButtonResourcePatch : ResourcePatch() {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
SwitchPreference("revanced_hide_floating_microphone_button")
|
||||
SwitchPreference("revanced_hide_floating_microphone_button"),
|
||||
)
|
||||
|
||||
fabButtonId = ResourceMappingPatch.resourceMappings.find { it.type == "id" && it.name == "fab" }?.id
|
||||
?: throw PatchException("Can not find required fab button resource id")
|
||||
fabButtonId = ResourceMappingPatch["id", "fab"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ import app.revanced.util.exception
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.youtube.layout.hide.general
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
@@ -11,19 +12,19 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.*
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.HideShowMoreButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint
|
||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverlayFingerprint
|
||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint
|
||||
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
@@ -33,6 +34,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
LithoFilterPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
HideLayoutComponentsResourcePatch::class,
|
||||
NavigationBarHookPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
@@ -54,14 +57,16 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37",
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object HideLayoutComponentsPatch : BytecodePatch(
|
||||
setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint),
|
||||
setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint, HideShowMoreButtonFingerprint),
|
||||
) {
|
||||
private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;"
|
||||
@@ -69,6 +74,8 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||
"Lapp/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter;"
|
||||
private const val CUSTOM_FILTER_CLASS_NAME =
|
||||
"Lapp/revanced/integrations/youtube/patches/components/CustomFilter;"
|
||||
private const val KEYWORD_FILTER_CLASS_NAME =
|
||||
"Lapp/revanced/integrations/youtube/patches/components/KeywordContentFilter;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
@@ -108,13 +115,27 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||
SwitchPreference("revanced_hide_compact_banner"),
|
||||
SwitchPreference("revanced_hide_feed_survey"),
|
||||
SwitchPreference("revanced_hide_for_you_shelf"),
|
||||
SwitchPreference("revanced_hide_horizontal_shelves"),
|
||||
SwitchPreference("revanced_hide_image_shelf"),
|
||||
SwitchPreference("revanced_hide_latest_posts_ads"),
|
||||
SwitchPreference("revanced_hide_mix_playlists"),
|
||||
SwitchPreference("revanced_hide_movies_section"),
|
||||
SwitchPreference("revanced_hide_notify_me_button"),
|
||||
SwitchPreference("revanced_hide_playables"),
|
||||
SwitchPreference("revanced_hide_search_result_recommendations"),
|
||||
SwitchPreference("revanced_hide_search_result_shelf_header"),
|
||||
SwitchPreference("revanced_hide_show_more_button"),
|
||||
PreferenceScreen(
|
||||
key = "revanced_hide_keyword_content_screen",
|
||||
sorting = Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_keyword_content_home"),
|
||||
SwitchPreference("revanced_hide_keyword_content_subscriptions"),
|
||||
SwitchPreference("revanced_hide_keyword_content_search"),
|
||||
TextPreference("revanced_hide_keyword_content_phrases", inputType = InputType.TEXT_MULTI_LINE),
|
||||
NonInteractivePreference("revanced_hide_keyword_content_about"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
@@ -136,19 +157,19 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||
|
||||
LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
|
||||
LithoFilterPatch.addFilter(DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME)
|
||||
LithoFilterPatch.addFilter(KEYWORD_FILTER_CLASS_NAME)
|
||||
LithoFilterPatch.addFilter(CUSTOM_FILTER_CLASS_NAME)
|
||||
|
||||
// region Mix playlists
|
||||
|
||||
ParseElementFromBufferFingerprint.result?.let { result ->
|
||||
val returnEmptyComponentInstruction =
|
||||
result.mutableMethod.getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
|
||||
ParseElementFromBufferFingerprint.resultOrThrow().let { result ->
|
||||
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex
|
||||
|
||||
result.mutableMethod.apply {
|
||||
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex
|
||||
val conversionContextRegister =
|
||||
getInstruction<TwoRegisterInstruction>(consumeByteBufferIndex - 2).registerA
|
||||
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD
|
||||
val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
|
||||
|
||||
addInstructionsWithLabels(
|
||||
consumeByteBufferIndex,
|
||||
@@ -160,15 +181,15 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
|
||||
)
|
||||
}
|
||||
} ?: throw ParseElementFromBufferFingerprint.exception
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Watermark (legacy code for old versions of YouTube)
|
||||
|
||||
ShowWatermarkFingerprint.also {
|
||||
it.resolve(context, PlayerOverlayFingerprint.result?.classDef ?: throw PlayerOverlayFingerprint.exception)
|
||||
}.result?.mutableMethod?.apply {
|
||||
it.resolve(context, PlayerOverlayFingerprint.resultOrThrow().classDef)
|
||||
}.resultOrThrow().mutableMethod.apply {
|
||||
val index = implementation!!.instructions.size - 5
|
||||
|
||||
removeInstruction(index)
|
||||
@@ -179,7 +200,26 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||
move-result p2
|
||||
""",
|
||||
)
|
||||
} ?: throw ShowWatermarkFingerprint.exception
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Show more button
|
||||
|
||||
HideShowMoreButtonFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val moveRegisterIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val viewRegister =
|
||||
getInstruction<OneRegisterInstruction>(moveRegisterIndex).registerA
|
||||
|
||||
val insertIndex = moveRegisterIndex + 1
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static { v$viewRegister }, " +
|
||||
"$LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideShowMoreButton(Landroid/view/View;)V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package app.revanced.patches.youtube.layout.hide.general
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
internal object HideLayoutComponentsResourcePatch : ResourcePatch() {
|
||||
internal var expandButtonDownId: Long = -1
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
expandButtonDownId = ResourceMappingPatch[
|
||||
"layout",
|
||||
"expand_button_down",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.youtube.layout.hide.general.fingerprints
|
||||
|
||||
import app.revanced.patches.youtube.layout.hide.general.HideLayoutComponentsResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object HideShowMoreButtonFingerprint : LiteralValueFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CONST,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
literalSupplier = { HideLayoutComponentsResourcePatch.expandButtonDownId }
|
||||
)
|
||||
@@ -45,7 +45,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43"
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
object HideInfocardsResourcePatch : ResourcePatch() {
|
||||
@@ -22,11 +22,12 @@ object HideInfocardsResourcePatch : ResourcePatch() {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||
SwitchPreference("revanced_hide_info_cards")
|
||||
SwitchPreference("revanced_hide_info_cards"),
|
||||
)
|
||||
|
||||
drawerResourceId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "id" && it.name == "info_cards_drawer_header"
|
||||
}.id
|
||||
drawerResourceId = ResourceMappingPatch[
|
||||
"id",
|
||||
"info_cards_drawer_header",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +1,12 @@
|
||||
package app.revanced.patches.youtube.layout.hide.loadmorebutton
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.youtube.layout.hide.loadmorebutton.fingerprints.HideLoadMoreButtonFingerprint
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import app.revanced.patches.youtube.layout.hide.general.HideLayoutComponentsPatch
|
||||
|
||||
@Patch(
|
||||
name = "Hide \'Load more\' button",
|
||||
description = "Adds an option to hide the button under videos that loads similar videos.",
|
||||
dependencies = [HideLoadMoreButtonResourcePatch::class],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"18.32.39",
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.37"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
@Deprecated("This patch class has been merged into HideLayoutComponentsPatch.")
|
||||
object HideLoadMoreButtonPatch : BytecodePatch(
|
||||
setOf(HideLoadMoreButtonFingerprint)
|
||||
dependencies = setOf(HideLayoutComponentsPatch::class)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/HideLoadMoreButtonPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
HideLoadMoreButtonFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val moveRegisterIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val viewRegister =
|
||||
getInstruction<OneRegisterInstruction>(moveRegisterIndex).registerA
|
||||
|
||||
val insertIndex = moveRegisterIndex + 1
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static { v$viewRegister }, " +
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideLoadMoreButton(Landroid/view/View;)V"
|
||||
)
|
||||
}
|
||||
} ?: throw HideLoadMoreButtonFingerprint.exception
|
||||
}
|
||||
}
|
||||
override fun execute(context: BytecodeContext) {}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.hide.loadmorebutton
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
SettingsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
AddResourcesPatch::class
|
||||
]
|
||||
)
|
||||
internal object HideLoadMoreButtonResourcePatch : ResourcePatch() {
|
||||
internal var expandButtonDownId: Long = -1
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||
SwitchPreference("revanced_hide_load_more_button")
|
||||
)
|
||||
|
||||
expandButtonDownId = ResourceMappingPatch.resourceMappings.single {
|
||||
it.type == "layout" && it.name == "expand_button_down"
|
||||
}.id
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user