mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-16 06:02:27 +01:00
Compare commits
104 Commits
v5.15.0-de
...
v5.20.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43d7cc7374 | ||
|
|
5ebd449f1f | ||
|
|
346a061df8 | ||
|
|
13e490a422 | ||
|
|
b4e8540bbc | ||
|
|
775c1baec2 | ||
|
|
9419fb8ec4 | ||
|
|
c510931eb0 | ||
|
|
7160699384 | ||
|
|
9db67a6eb2 | ||
|
|
e684d87dd3 | ||
|
|
2d1752a1eb | ||
|
|
c9ff7092fe | ||
|
|
d451bc6d6d | ||
|
|
741fd36872 | ||
|
|
517f8cf59a | ||
|
|
b78fb24435 | ||
|
|
a3faccb21b | ||
|
|
5f0fddc122 | ||
|
|
854a18ff72 | ||
|
|
b994a16bdc | ||
|
|
f68d06dbf3 | ||
|
|
04c6a2e5f4 | ||
|
|
e6ae55fa99 | ||
|
|
fb62474ff4 | ||
|
|
e084f01fd0 | ||
|
|
d573386e0f | ||
|
|
0f3aeb35e5 | ||
|
|
e30f593af0 | ||
|
|
df965b8a9b | ||
|
|
654587a75e | ||
|
|
9956833781 | ||
|
|
c585b26188 | ||
|
|
de0d11fcfb | ||
|
|
d321504fcf | ||
|
|
6005c97bf5 | ||
|
|
e404d84c83 | ||
|
|
1abed31968 | ||
|
|
a75a88d3c6 | ||
|
|
3d67d90473 | ||
|
|
fa1e137a43 | ||
|
|
ac71a53c73 | ||
|
|
0bff207efc | ||
|
|
e1a8b388a5 | ||
|
|
628d18489c | ||
|
|
36772b8b2e | ||
|
|
49c849979f | ||
|
|
0bdb8cdf2b | ||
|
|
2035c9e2e9 | ||
|
|
7cb38fd3fc | ||
|
|
8ed9d5bf08 | ||
|
|
cd467d6244 | ||
|
|
fdefb67d02 | ||
|
|
5274cd18f0 | ||
|
|
3d68c06146 | ||
|
|
ef3d5bafd5 | ||
|
|
2d7b1b09af | ||
|
|
0572d48fde | ||
|
|
37984b8b99 | ||
|
|
6e63193f06 | ||
|
|
b2384b22a5 | ||
|
|
ccb76983ff | ||
|
|
318b55b8fe | ||
|
|
49ade9efbc | ||
|
|
d77515bd68 | ||
|
|
087bf1e152 | ||
|
|
c2994d583d | ||
|
|
127b0a63fe | ||
|
|
27aafd0ee1 | ||
|
|
49c54c0e54 | ||
|
|
842ba4fc4d | ||
|
|
66ecadce4f | ||
|
|
73ca04da5e | ||
|
|
a5d26208c1 | ||
|
|
497291c478 | ||
|
|
b24278a544 | ||
|
|
135f9ead3c | ||
|
|
ca4f960171 | ||
|
|
7f228cc535 | ||
|
|
bf91e127d8 | ||
|
|
f07fc1ad93 | ||
|
|
c84be120bd | ||
|
|
e67f390e2b | ||
|
|
4d910fea93 | ||
|
|
72adbe5519 | ||
|
|
54d49b774e | ||
|
|
283bb31567 | ||
|
|
2724fcbd27 | ||
|
|
7c28193579 | ||
|
|
cd1ee814c4 | ||
|
|
d9ccd73b5f | ||
|
|
5c5a1e4b8b | ||
|
|
66a2ee2416 | ||
|
|
d8c276cf96 | ||
|
|
d5845abd08 | ||
|
|
54eef22ce7 | ||
|
|
e287bdc59d | ||
|
|
20a82ef956 | ||
|
|
1e29da9e06 | ||
|
|
56e6a90a90 | ||
|
|
76d32e21c2 | ||
|
|
54a7afa540 | ||
|
|
ef86438bac | ||
|
|
0683cedac0 |
2
.github/workflows/pull_strings.yml
vendored
2
.github/workflows/pull_strings.yml
vendored
@@ -2,7 +2,7 @@ name: Pull strings
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 */8 * * *"
|
- cron: "0 */12 * * *"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
378
CHANGELOG.md
378
CHANGELOG.md
@@ -1,3 +1,381 @@
|
|||||||
|
# [5.20.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.4...v5.20.0-dev.5) (2025-04-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - Swipe controls:** Add option to change volume swipe sensitivity (step size) ([#4557](https://github.com/ReVanced/revanced-patches/issues/4557)) ([8957325](https://github.com/ReVanced/revanced-patches/commit/8957325d78eb42e087c4c1ff0abedb2146aa4423))
|
||||||
|
|
||||||
|
# [5.20.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.3...v5.20.0-dev.4) (2025-04-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Unlock Spotify Premium:** Remove premium restriction for 'Spotify Connect' ([#4782](https://github.com/ReVanced/revanced-patches/issues/4782)) ([50f5b1a](https://github.com/ReVanced/revanced-patches/commit/50f5b1ac54372542d76e87626f00ddefb54da125))
|
||||||
|
|
||||||
|
# [5.20.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.2...v5.20.0-dev.3) (2025-04-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Remove background playback restrictions:** Restore PiP button functionality after screen is unlocked ([6837348](https://github.com/ReVanced/revanced-patches/commit/6837348c45156d6743a63fef8b6e045087afbda8))
|
||||||
|
|
||||||
|
# [5.20.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.1...v5.20.0-dev.2) (2025-04-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify - Custom theme:** Add option to use unmodified player background gradient ([#4741](https://github.com/ReVanced/revanced-patches/issues/4741)) ([0ee3693](https://github.com/ReVanced/revanced-patches/commit/0ee36939f43f325afca37119db1cf1af3b63be27))
|
||||||
|
|
||||||
|
# [5.20.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.1...v5.20.0-dev.1) (2025-04-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add `Set target SDK version 34` patch (Disable edge-to-edge display) ([#4780](https://github.com/ReVanced/revanced-patches/issues/4780)) ([dcf6178](https://github.com/ReVanced/revanced-patches/commit/dcf6178f19f86dd1b57d54c855b8c47b086dd33a))
|
||||||
|
|
||||||
|
## [5.19.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.0...v5.19.1) (2025-04-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos:** Restore patching with ReVanced Manager ([#4773](https://github.com/ReVanced/revanced-patches/issues/4773)) ([3e18e86](https://github.com/ReVanced/revanced-patches/commit/3e18e868bbd9fd0600fe81a7fe8767b4bd89a00e))
|
||||||
|
* **Spotify:** Restore patching with ReVanced Manager ([#4769](https://github.com/ReVanced/revanced-patches/issues/4769)) ([89d44da](https://github.com/ReVanced/revanced-patches/commit/89d44da171c3f56f13112d1d82bc4ea4a56c7c06))
|
||||||
|
|
||||||
|
## [5.19.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.19.1-dev.1...v5.19.1-dev.2) (2025-04-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos:** Restore patching with ReVanced Manager ([#4773](https://github.com/ReVanced/revanced-patches/issues/4773)) ([3e18e86](https://github.com/ReVanced/revanced-patches/commit/3e18e868bbd9fd0600fe81a7fe8767b4bd89a00e))
|
||||||
|
|
||||||
|
## [5.19.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.0...v5.19.1-dev.1) (2025-04-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify:** Restore patching with ReVanced Manager ([#4769](https://github.com/ReVanced/revanced-patches/issues/4769)) ([89d44da](https://github.com/ReVanced/revanced-patches/commit/89d44da171c3f56f13112d1d82bc4ea4a56c7c06))
|
||||||
|
|
||||||
|
# [5.19.0](https://github.com/ReVanced/revanced-patches/compare/v5.18.0...v5.19.0) (2025-04-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos - Restore hidden 'Back up while charging' toggle:** Constrain to last working app target ([#4761](https://github.com/ReVanced/revanced-patches/issues/4761)) ([152bb7c](https://github.com/ReVanced/revanced-patches/commit/152bb7c3ee7cf36bc07460e7a3444631ec540441))
|
||||||
|
* **Google Photos:** Remove obsolete non functional patch `Restore hidden 'Back up while charging' toggle` ([#4764](https://github.com/ReVanced/revanced-patches/issues/4764)) ([56e48f4](https://github.com/ReVanced/revanced-patches/commit/56e48f4c89da51f81ff11a79a164eaa5b440690e))
|
||||||
|
* **Spotify - Custom theme:** Override more color resources ([#4690](https://github.com/ReVanced/revanced-patches/issues/4690)) ([d7a7a0b](https://github.com/ReVanced/revanced-patches/commit/d7a7a0b982dbafa181b04f984a5f7618fb067c2a))
|
||||||
|
* **Spotify - Unlock Spotify Premium:** Remove restrictions for Google voice assistant ([#4702](https://github.com/ReVanced/revanced-patches/issues/4702)) ([106202f](https://github.com/ReVanced/revanced-patches/commit/106202f9ebb7699c4ba4ae46b82133e35f1ac6b9))
|
||||||
|
* **Spotify:** Remove ads sections from home ([#4722](https://github.com/ReVanced/revanced-patches/issues/4722)) ([0b9a5e7](https://github.com/ReVanced/revanced-patches/commit/0b9a5e7f89a89d971762b3539166d4f145111481))
|
||||||
|
* **Twitter - Hide recommended users:** Make hiding work again by filtering for new entryId prefix ([#4456](https://github.com/ReVanced/revanced-patches/issues/4456)) ([ff846b0](https://github.com/ReVanced/revanced-patches/commit/ff846b0b7ef5060caaffedb08c1f901172f5b2d1))
|
||||||
|
* **YouTube - Hide layout components:** Do not hide video description music/game links if hide horizontal shelves is enabled ([3864f35](https://github.com/ReVanced/revanced-patches/commit/3864f3550153617e23ad9979fb543d8a7fb4dc0a))
|
||||||
|
* **YouTube - Hide player flyout menu items:** Show more detailed summary text for 'Hide Audio track' if using Android spoof client ([#4756](https://github.com/ReVanced/revanced-patches/issues/4756)) ([b67bbb2](https://github.com/ReVanced/revanced-patches/commit/b67bbb299669336addb68cf52a8ce5b39c68cec0))
|
||||||
|
* **YouTube - Remove background playback restrictions:** Do not show media controls when playing Shorts from the feed ([2ed675c](https://github.com/ReVanced/revanced-patches/commit/2ed675cdd058fb5876381a9d30dee5263f6b2e26))
|
||||||
|
* **YouTube - Return YouTube Dislike:** Correctly update label after disliking a Short with 20.07 ([0bb3e32](https://github.com/ReVanced/revanced-patches/commit/0bb3e32244fa10809aee5c4e549f77ed4054537e))
|
||||||
|
* **YouTube - Return YouTube Dislike:** Fix inconsistent label after disliking a Short ([ea92a2e](https://github.com/ReVanced/revanced-patches/commit/ea92a2e36c7aab3bd115f7d0ec40467179485b32))
|
||||||
|
* **YouTube - Seekbar:** Correctly hide the feed seekbar with target 20.07 ([ddc6e4c](https://github.com/ReVanced/revanced-patches/commit/ddc6e4c34fe35fa34bd859bf34e25645a23dbdc9))
|
||||||
|
* **YouTube:** Combine multiple seekbar patches into a single patch ([#4705](https://github.com/ReVanced/revanced-patches/issues/4705)) ([503b7eb](https://github.com/ReVanced/revanced-patches/commit/503b7eb8d413ef7f248394f128f3b2a6f3192ba6))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Angulus:** Add `Hide ads` patch ([#4604](https://github.com/ReVanced/revanced-patches/issues/4604)) ([87c86b5](https://github.com/ReVanced/revanced-patches/commit/87c86b53a91b0054ac892a3f02bbe7bf83bbf813))
|
||||||
|
* **Messenger:** Add `Remove Meta AI tab` patch ([#4726](https://github.com/ReVanced/revanced-patches/issues/4726)) ([e3fad97](https://github.com/ReVanced/revanced-patches/commit/e3fad97484d7eb962aeb53d44a0047b34a881071))
|
||||||
|
* **Photomath:** Support latest version ([#4672](https://github.com/ReVanced/revanced-patches/issues/4672)) ([8e16483](https://github.com/ReVanced/revanced-patches/commit/8e1648322948151e4565fb0d86e0f37d0a02d73f))
|
||||||
|
* **Proton Mail:** Add `Remove 'Sent from' signature` patch ([#4514](https://github.com/ReVanced/revanced-patches/issues/4514)) ([34c14c9](https://github.com/ReVanced/revanced-patches/commit/34c14c9b443092824d035afd77adb678c6f89e3e))
|
||||||
|
* **Spotify:** Add `Check environment` patch ([#4765](https://github.com/ReVanced/revanced-patches/issues/4765)) ([6d7101c](https://github.com/ReVanced/revanced-patches/commit/6d7101cb2e546e01a934eff9cad1264367aeafe3))
|
||||||
|
* **Spotify:** Add limited support for version `8.6.98.900` (last version that supports Kenwood and Pioneer car stereos) ([#4750](https://github.com/ReVanced/revanced-patches/issues/4750)) ([a3fde87](https://github.com/ReVanced/revanced-patches/commit/a3fde874af993125ba7a741820e7bd48e3641b84))
|
||||||
|
* **Strava - Disable subscription suggestions:** Make compatible with latest version ([#4739](https://github.com/ReVanced/revanced-patches/issues/4739)) ([649a2c0](https://github.com/ReVanced/revanced-patches/commit/649a2c06161c72a2040b179dbed5b415847d7527))
|
||||||
|
* **YouTube - Settings:** Add icons to the ReVanced settings ([#4496](https://github.com/ReVanced/revanced-patches/issues/4496)) ([d0c85f0](https://github.com/ReVanced/revanced-patches/commit/d0c85f044083d720c63a8ea4ff15d42eefeb9db7))
|
||||||
|
|
||||||
|
# [5.19.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.16...v5.19.0-dev.17) (2025-04-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify:** Add `Check environment` patch ([#4765](https://github.com/ReVanced/revanced-patches/issues/4765)) ([6d7101c](https://github.com/ReVanced/revanced-patches/commit/6d7101cb2e546e01a934eff9cad1264367aeafe3))
|
||||||
|
|
||||||
|
# [5.19.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.15...v5.19.0-dev.16) (2025-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos:** Remove obsolete non functional patch `Restore hidden 'Back up while charging' toggle` ([#4764](https://github.com/ReVanced/revanced-patches/issues/4764)) ([56e48f4](https://github.com/ReVanced/revanced-patches/commit/56e48f4c89da51f81ff11a79a164eaa5b440690e))
|
||||||
|
|
||||||
|
# [5.19.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.14...v5.19.0-dev.15) (2025-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos - Restore hidden 'Back up while charging' toggle:** Constrain to last working app target ([#4761](https://github.com/ReVanced/revanced-patches/issues/4761)) ([152bb7c](https://github.com/ReVanced/revanced-patches/commit/152bb7c3ee7cf36bc07460e7a3444631ec540441))
|
||||||
|
|
||||||
|
# [5.19.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.13...v5.19.0-dev.14) (2025-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Unlock Spotify Premium:** Remove restrictions for Google voice assistant ([#4702](https://github.com/ReVanced/revanced-patches/issues/4702)) ([106202f](https://github.com/ReVanced/revanced-patches/commit/106202f9ebb7699c4ba4ae46b82133e35f1ac6b9))
|
||||||
|
|
||||||
|
# [5.19.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.12...v5.19.0-dev.13) (2025-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify:** Add limited support for version `8.6.98.900` (last version that supports Kenwood and Pioneer car stereos) ([#4750](https://github.com/ReVanced/revanced-patches/issues/4750)) ([a3fde87](https://github.com/ReVanced/revanced-patches/commit/a3fde874af993125ba7a741820e7bd48e3641b84))
|
||||||
|
|
||||||
|
# [5.19.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.11...v5.19.0-dev.12) (2025-04-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Strava - Disable subscription suggestions:** Make compatible with latest version ([#4739](https://github.com/ReVanced/revanced-patches/issues/4739)) ([649a2c0](https://github.com/ReVanced/revanced-patches/commit/649a2c06161c72a2040b179dbed5b415847d7527))
|
||||||
|
|
||||||
|
# [5.19.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.10...v5.19.0-dev.11) (2025-04-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Messenger:** Add `Remove Meta AI tab` patch ([#4726](https://github.com/ReVanced/revanced-patches/issues/4726)) ([e3fad97](https://github.com/ReVanced/revanced-patches/commit/e3fad97484d7eb962aeb53d44a0047b34a881071))
|
||||||
|
|
||||||
|
# [5.19.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.9...v5.19.0-dev.10) (2025-04-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Hide layout components:** Do not hide video description music/game links if hide horizontal shelves is enabled ([3864f35](https://github.com/ReVanced/revanced-patches/commit/3864f3550153617e23ad9979fb543d8a7fb4dc0a))
|
||||||
|
|
||||||
|
# [5.19.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.8...v5.19.0-dev.9) (2025-04-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Hide player flyout menu items:** Show more detailed summary text for 'Hide Audio track' if using Android spoof client ([#4756](https://github.com/ReVanced/revanced-patches/issues/4756)) ([b67bbb2](https://github.com/ReVanced/revanced-patches/commit/b67bbb299669336addb68cf52a8ce5b39c68cec0))
|
||||||
|
|
||||||
|
# [5.19.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.7...v5.19.0-dev.8) (2025-04-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Return YouTube Dislike:** Fix inconsistent label after disliking a Short ([ea92a2e](https://github.com/ReVanced/revanced-patches/commit/ea92a2e36c7aab3bd115f7d0ec40467179485b32))
|
||||||
|
|
||||||
|
# [5.19.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.6...v5.19.0-dev.7) (2025-04-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Return YouTube Dislike:** Correctly update label after disliking a Short with 20.07 ([0bb3e32](https://github.com/ReVanced/revanced-patches/commit/0bb3e32244fa10809aee5c4e549f77ed4054537e))
|
||||||
|
|
||||||
|
# [5.19.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.5...v5.19.0-dev.6) (2025-04-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify:** Remove ads sections from home ([#4722](https://github.com/ReVanced/revanced-patches/issues/4722)) ([0b9a5e7](https://github.com/ReVanced/revanced-patches/commit/0b9a5e7f89a89d971762b3539166d4f145111481))
|
||||||
|
|
||||||
|
# [5.19.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.4...v5.19.0-dev.5) (2025-04-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Custom theme:** Override more color resources ([#4690](https://github.com/ReVanced/revanced-patches/issues/4690)) ([d7a7a0b](https://github.com/ReVanced/revanced-patches/commit/d7a7a0b982dbafa181b04f984a5f7618fb067c2a))
|
||||||
|
|
||||||
|
# [5.19.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.3...v5.19.0-dev.4) (2025-04-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Seekbar:** Correctly hide the feed seekbar with target 20.07 ([ddc6e4c](https://github.com/ReVanced/revanced-patches/commit/ddc6e4c34fe35fa34bd859bf34e25645a23dbdc9))
|
||||||
|
|
||||||
|
# [5.19.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.2...v5.19.0-dev.3) (2025-04-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Proton Mail:** Add `Remove 'Sent from' signature` patch ([#4514](https://github.com/ReVanced/revanced-patches/issues/4514)) ([34c14c9](https://github.com/ReVanced/revanced-patches/commit/34c14c9b443092824d035afd77adb678c6f89e3e))
|
||||||
|
|
||||||
|
# [5.19.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.1...v5.19.0-dev.2) (2025-04-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - Settings:** Add icons to the ReVanced settings ([#4496](https://github.com/ReVanced/revanced-patches/issues/4496)) ([d0c85f0](https://github.com/ReVanced/revanced-patches/commit/d0c85f044083d720c63a8ea4ff15d42eefeb9db7))
|
||||||
|
|
||||||
|
# [5.19.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.18.1-dev.2...v5.19.0-dev.1) (2025-04-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Twitter - Hide recommended users:** Make hiding work again by filtering for new entryId prefix ([#4456](https://github.com/ReVanced/revanced-patches/issues/4456)) ([ff846b0](https://github.com/ReVanced/revanced-patches/commit/ff846b0b7ef5060caaffedb08c1f901172f5b2d1))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Angulus:** Add `Hide ads` patch ([#4604](https://github.com/ReVanced/revanced-patches/issues/4604)) ([87c86b5](https://github.com/ReVanced/revanced-patches/commit/87c86b53a91b0054ac892a3f02bbe7bf83bbf813))
|
||||||
|
* **Photomath:** Support latest version ([#4672](https://github.com/ReVanced/revanced-patches/issues/4672)) ([8e16483](https://github.com/ReVanced/revanced-patches/commit/8e1648322948151e4565fb0d86e0f37d0a02d73f))
|
||||||
|
|
||||||
|
## [5.18.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.18.1-dev.1...v5.18.1-dev.2) (2025-04-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube:** Combine multiple seekbar patches into a single patch ([#4705](https://github.com/ReVanced/revanced-patches/issues/4705)) ([503b7eb](https://github.com/ReVanced/revanced-patches/commit/503b7eb8d413ef7f248394f128f3b2a6f3192ba6))
|
||||||
|
|
||||||
|
## [5.18.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.18.0...v5.18.1-dev.1) (2025-03-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Remove background playback restrictions:** Do not show media controls when playing Shorts from the feed ([2ed675c](https://github.com/ReVanced/revanced-patches/commit/2ed675cdd058fb5876381a9d30dee5263f6b2e26))
|
||||||
|
|
||||||
|
# [5.18.0](https://github.com/ReVanced/revanced-patches/compare/v5.17.0...v5.18.0) (2025-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify:** Ignore optional attributes if not present ([#4688](https://github.com/ReVanced/revanced-patches/issues/4688)) ([84f5854](https://github.com/ReVanced/revanced-patches/commit/84f585492e4be3604c6c7680ffb3bebcea5a675f))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube:** Support version `20.07.39` ([#4677](https://github.com/ReVanced/revanced-patches/issues/4677)) ([c1379f6](https://github.com/ReVanced/revanced-patches/commit/c1379f6e520c683d2c9d6a490a69ca542168b3b3))
|
||||||
|
|
||||||
|
# [5.18.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.18.0-dev.1...v5.18.0-dev.2) (2025-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify:** Ignore optional attributes if not present ([#4688](https://github.com/ReVanced/revanced-patches/issues/4688)) ([84f5854](https://github.com/ReVanced/revanced-patches/commit/84f585492e4be3604c6c7680ffb3bebcea5a675f))
|
||||||
|
|
||||||
|
# [5.18.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.17.0...v5.18.0-dev.1) (2025-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube:** Support version `20.07.39` ([#4677](https://github.com/ReVanced/revanced-patches/issues/4677)) ([c1379f6](https://github.com/ReVanced/revanced-patches/commit/c1379f6e520c683d2c9d6a490a69ca542168b3b3))
|
||||||
|
|
||||||
|
# [5.17.0](https://github.com/ReVanced/revanced-patches/compare/v5.16.1...v5.17.0) (2025-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Facebook - Hide 'Sponsored Stories':** Constrain patch to latest compatible version ([#4657](https://github.com/ReVanced/revanced-patches/issues/4657)) ([46bd1c8](https://github.com/ReVanced/revanced-patches/commit/46bd1c829acd5f83600025e0ceb7d482ae80be69))
|
||||||
|
* **Spotify - Unlock Premium:** Override additional attributes ([#4651](https://github.com/ReVanced/revanced-patches/issues/4651)) ([568b40d](https://github.com/ReVanced/revanced-patches/commit/568b40da9692eae9039bbb3cec513a61ca627c24))
|
||||||
|
* **Spotify - Unlock Premium:** Use correct patch description convention ([a486522](https://github.com/ReVanced/revanced-patches/commit/a4865228f8481d2efc8fbf4e90902a03289d9a3f))
|
||||||
|
* **X / Twitter:** Constrain patches to latest compatible versions ([#4683](https://github.com/ReVanced/revanced-patches/issues/4683)) ([f579728](https://github.com/ReVanced/revanced-patches/commit/f5797289f45186052537982c7f5db6f2b0769aee))
|
||||||
|
* **YouTube - Navigation buttons:** Add user dialog message to 'Disable translucent status bar' ([a4a0e68](https://github.com/ReVanced/revanced-patches/commit/a4a0e6869e23d15ee09262460f4e290c90629eeb))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify - Unlock Premium:** Disable the "Spotify Premium" upsell experiment in context menus ([9a10ee4](https://github.com/ReVanced/revanced-patches/commit/9a10ee4d22fb53da2012a182e038749d3ad72377))
|
||||||
|
|
||||||
|
# [5.17.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.17.0-dev.3...v5.17.0-dev.4) (2025-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter:** Constrain patches to latest compatible versions ([#4683](https://github.com/ReVanced/revanced-patches/issues/4683)) ([f579728](https://github.com/ReVanced/revanced-patches/commit/f5797289f45186052537982c7f5db6f2b0769aee))
|
||||||
|
|
||||||
|
# [5.17.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.17.0-dev.2...v5.17.0-dev.3) (2025-03-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Unlock Premium:** Override additional attributes ([#4651](https://github.com/ReVanced/revanced-patches/issues/4651)) ([568b40d](https://github.com/ReVanced/revanced-patches/commit/568b40da9692eae9039bbb3cec513a61ca627c24))
|
||||||
|
|
||||||
|
# [5.17.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.17.0-dev.1...v5.17.0-dev.2) (2025-03-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Navigation buttons:** Add user dialog message to 'Disable translucent status bar' ([a4a0e68](https://github.com/ReVanced/revanced-patches/commit/a4a0e6869e23d15ee09262460f4e290c90629eeb))
|
||||||
|
|
||||||
|
# [5.17.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.2-dev.1...v5.17.0-dev.1) (2025-03-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Unlock Premium:** Use correct patch description convention ([a486522](https://github.com/ReVanced/revanced-patches/commit/a4865228f8481d2efc8fbf4e90902a03289d9a3f))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify - Unlock Premium:** Disable the "Spotify Premium" upsell experiment in context menus ([9a10ee4](https://github.com/ReVanced/revanced-patches/commit/9a10ee4d22fb53da2012a182e038749d3ad72377))
|
||||||
|
|
||||||
|
## [5.16.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.1...v5.16.2-dev.1) (2025-03-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Facebook - Hide 'Sponsored Stories':** Constrain patch to latest compatible version ([#4657](https://github.com/ReVanced/revanced-patches/issues/4657)) ([46bd1c8](https://github.com/ReVanced/revanced-patches/commit/46bd1c829acd5f83600025e0ceb7d482ae80be69))
|
||||||
|
|
||||||
|
## [5.16.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.0...v5.16.1) (2025-03-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Unlock Premium:** Override streaming attribute attempting to fix streaming issues ([06be36c](https://github.com/ReVanced/revanced-patches/commit/06be36cddf3430b4179dff696b3d15718cd6963b))
|
||||||
|
|
||||||
|
## [5.16.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.0...v5.16.1-dev.1) (2025-03-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify - Unlock Premium:** Override streaming attribute attempting to fix streaming issues ([06be36c](https://github.com/ReVanced/revanced-patches/commit/06be36cddf3430b4179dff696b3d15718cd6963b))
|
||||||
|
|
||||||
|
# [5.16.0](https://github.com/ReVanced/revanced-patches/compare/v5.15.0...v5.16.0) (2025-03-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Settings:** System navigation bar is located above the settings ui on Android 15+ ([f7497be](https://github.com/ReVanced/revanced-patches/commit/f7497be2c5e4abcde6eb55b84955124a28f55cae))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([f048c50](https://github.com/ReVanced/revanced-patches/commit/f048c50e56fc1f5a5c607860be4206ef83b528fe))
|
||||||
|
* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([e9b7f26](https://github.com/ReVanced/revanced-patches/commit/e9b7f263f739bd130f6ea79913851a52355977c5))
|
||||||
|
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([521fd48](https://github.com/ReVanced/revanced-patches/commit/521fd48602432ab436d8711c19d7130b2b05af12))
|
||||||
|
|
||||||
|
# [5.16.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.16.0-dev.1...v5.16.0-dev.2) (2025-03-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([f048c50](https://github.com/ReVanced/revanced-patches/commit/f048c50e56fc1f5a5c607860be4206ef83b528fe))
|
||||||
|
|
||||||
|
# [5.16.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.15.0...v5.16.0-dev.1) (2025-03-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Settings:** System navigation bar is located above the settings ui on Android 15+ ([f7497be](https://github.com/ReVanced/revanced-patches/commit/f7497be2c5e4abcde6eb55b84955124a28f55cae))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([e9b7f26](https://github.com/ReVanced/revanced-patches/commit/e9b7f263f739bd130f6ea79913851a52355977c5))
|
||||||
|
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([521fd48](https://github.com/ReVanced/revanced-patches/commit/521fd48602432ab436d8711c19d7130b2b05af12))
|
||||||
|
|
||||||
|
# [5.15.0](https://github.com/ReVanced/revanced-patches/compare/v5.14.0...v5.15.0) (2025-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof app version:** Change oldest spoof target to 19.01.34 ([5012439](https://github.com/ReVanced/revanced-patches/commit/5012439a8e53b2a4ab5e85c47976e1ab28a51208))
|
||||||
|
* **YouTube - Spoof app version:** Remove broken spoof targets that YouTube no longer supports ([#4610](https://github.com/ReVanced/revanced-patches/issues/4610)) ([883fbe7](https://github.com/ReVanced/revanced-patches/commit/883fbe71233c57cb1241e57c122b43f40722acc7))
|
||||||
|
* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([49797fe](https://github.com/ReVanced/revanced-patches/commit/49797fe8d0c4a0981ef621a31356c4315ae3777b))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - SponsorBlock:** Add opacity setting to category segment colors ([#4582](https://github.com/ReVanced/revanced-patches/issues/4582)) ([6e8ffba](https://github.com/ReVanced/revanced-patches/commit/6e8ffbade9e03658f725622631e44dabf2995861))
|
||||||
|
|
||||||
|
# [5.15.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.3...v5.15.0-dev.4) (2025-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof app version:** Change oldest spoof target to 19.01.34 ([5012439](https://github.com/ReVanced/revanced-patches/commit/5012439a8e53b2a4ab5e85c47976e1ab28a51208))
|
||||||
|
|
||||||
# [5.15.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.2...v5.15.0-dev.3) (2025-03-20)
|
# [5.15.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.2...v5.15.0-dev.3) (2025-03-20)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -799,4 +800,14 @@ public class Utils {
|
|||||||
builder.getContext().setTheme(editTextDialogStyle);
|
builder.getContext().setTheme(editTextDialogStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a color resource or hex code to an int representation of the color.
|
||||||
|
*/
|
||||||
|
public static int getColorFromString(String colorString) throws IllegalArgumentException, Resources.NotFoundException {
|
||||||
|
if (colorString.startsWith("#")) {
|
||||||
|
return Color.parseColor(colorString);
|
||||||
|
}
|
||||||
|
return getResourceColor(colorString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ public class BaseSettings {
|
|||||||
|
|
||||||
public static final EnumSetting<AppLanguage> REVANCED_LANGUAGE = new EnumSetting<>("revanced_language", AppLanguage.DEFAULT, true, "revanced_language_user_dialog_message");
|
public static final EnumSetting<AppLanguage> REVANCED_LANGUAGE = new EnumSetting<>("revanced_language", AppLanguage.DEFAULT, true, "revanced_language_user_dialog_message");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the icons declared in the preferences created during patching. If no icons or styles are declared then this setting does nothing.
|
||||||
|
*/
|
||||||
|
public static final BooleanSetting SHOW_MENU_ICONS = new BooleanSetting("revanced_show_menu_icons", TRUE, true);
|
||||||
|
|
||||||
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
|
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
|
||||||
public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
||||||
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
|
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize this instance, and do any custom behavior.
|
* Initialize this instance, and do any custom behavior.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -95,7 +94,10 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
* so all app specific {@link Setting} instances are loaded before this method returns.
|
* so all app specific {@link Setting} instances are loaded before this method returns.
|
||||||
*/
|
*/
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
final var identifier = Utils.getResourceIdentifier("revanced_prefs", "xml");
|
String preferenceResourceName = BaseSettings.SHOW_MENU_ICONS.get()
|
||||||
|
? "revanced_prefs_icons"
|
||||||
|
: "revanced_prefs";
|
||||||
|
final var identifier = Utils.getResourceIdentifier(preferenceResourceName, "xml");
|
||||||
if (identifier == 0) return;
|
if (identifier == 0) return;
|
||||||
addPreferencesFromResource(identifier);
|
addPreferencesFromResource(identifier);
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,21 @@ public class SpoofVideoStreamsPatch {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
* Turns off a feature flag that interferes with video playback.
|
||||||
|
*/
|
||||||
|
public static boolean usePlaybackStartFeatureFlag(boolean original) {
|
||||||
|
if (original) {
|
||||||
|
Logger.printDebug(() -> "usePlaybackStartFeatureFlag is set on");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SPOOF_STREAMING_DATA) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
|
|||||||
16
extensions/spotify/build.gradle.kts
Normal file
16
extensions/spotify/build.gradle.kts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
dependencies {
|
||||||
|
compileOnly(project(":extensions:shared:library"))
|
||||||
|
compileOnly(project(":extensions:spotify:stub"))
|
||||||
|
compileOnly(libs.annotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
}
|
||||||
1
extensions/spotify/src/main/AndroidManifest.xml
Normal file
1
extensions/spotify/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest/>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package app.revanced.extension.spotify.layout.theme;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class CustomThemePatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static long getThemeColor(String colorString) {
|
||||||
|
try {
|
||||||
|
return Utils.getColorFromString(colorString);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "Invalid custom color: " + colorString, ex);
|
||||||
|
return Color.BLACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
extensions/spotify/stub/build.gradle.kts
Normal file
17
extensions/spotify/stub/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
id(libs.plugins.android.library.get().pluginId)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "app.revanced.extension"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = 26
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
}
|
||||||
1
extensions/spotify/stub/src/main/AndroidManifest.xml
Normal file
1
extensions/spotify/stub/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest/>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.spotify.home.evopage.homeapi.proto;
|
||||||
|
|
||||||
|
public final class Section {
|
||||||
|
public static final int VIDEO_BRAND_AD_FIELD_NUMBER = 20;
|
||||||
|
public static final int IMAGE_BRAND_AD_FIELD_NUMBER = 21;
|
||||||
|
public int featureTypeCase_;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.spotify.remoteconfig.internal;
|
||||||
|
|
||||||
|
public final class AccountAttribute {
|
||||||
|
public Object value_;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.spotify.useraccount.v1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for target 8.6.98.900. Class is still present in newer app targets.
|
||||||
|
*/
|
||||||
|
public class AccountAttribute {
|
||||||
|
public Object value_;
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import app.revanced.extension.tiktok.settings.preference.categories.DownloadsPre
|
|||||||
import app.revanced.extension.tiktok.settings.preference.categories.FeedFilterPreferenceCategory;
|
import app.revanced.extension.tiktok.settings.preference.categories.FeedFilterPreferenceCategory;
|
||||||
import app.revanced.extension.tiktok.settings.preference.categories.ExtensionPreferenceCategory;
|
import app.revanced.extension.tiktok.settings.preference.categories.ExtensionPreferenceCategory;
|
||||||
import app.revanced.extension.tiktok.settings.preference.categories.SimSpoofPreferenceCategory;
|
import app.revanced.extension.tiktok.settings.preference.categories.SimSpoofPreferenceCategory;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preference fragment for ReVanced settings
|
* Preference fragment for ReVanced settings
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ internal object TwiFucker {
|
|||||||
|
|
||||||
private fun JSONObject.entryIsWhoToFollow(): Boolean =
|
private fun JSONObject.entryIsWhoToFollow(): Boolean =
|
||||||
optString("entryId").let {
|
optString("entryId").let {
|
||||||
it.startsWith("whoToFollow-") || it.startsWith("who-to-follow-") || it.startsWith("connect-module-")
|
it.startsWith("whoToFollow-") || it.startsWith("who-to-follow-") || it.startsWith("connect-module-") || it.startsWith("who-to-subscribe-")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JSONObject.itemContainsPromotedUser(): Boolean =
|
private fun JSONObject.itemContainsPromotedUser(): Boolean =
|
||||||
|
|||||||
@@ -45,13 +45,24 @@ public class ThemeHelper {
|
|||||||
return "@color/yt_black3";
|
return "@color/yt_black3";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getThemeColor(String resourceName, int defaultColor) {
|
||||||
|
try {
|
||||||
|
return Utils.getColorFromString(resourceName);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// User entered an invalid custom theme color.
|
||||||
|
// Normally this should never be reached, and no localized strings are needed.
|
||||||
|
Utils.showToastLong("Invalid custom theme color: " + resourceName);
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The dark theme color as specified by the Theme patch (if included),
|
* @return The dark theme color as specified by the Theme patch (if included),
|
||||||
* or the dark mode background color unpatched YT uses.
|
* or the dark mode background color unpatched YT uses.
|
||||||
*/
|
*/
|
||||||
public static int getDarkThemeColor() {
|
public static int getDarkThemeColor() {
|
||||||
if (darkThemeColor == null) {
|
if (darkThemeColor == null) {
|
||||||
darkThemeColor = getColorInt(darkThemeResourceName());
|
darkThemeColor = getThemeColor(darkThemeResourceName(), Color.BLACK);
|
||||||
}
|
}
|
||||||
return darkThemeColor;
|
return darkThemeColor;
|
||||||
}
|
}
|
||||||
@@ -71,18 +82,11 @@ public class ThemeHelper {
|
|||||||
*/
|
*/
|
||||||
public static int getLightThemeColor() {
|
public static int getLightThemeColor() {
|
||||||
if (lightThemeColor == null) {
|
if (lightThemeColor == null) {
|
||||||
lightThemeColor = getColorInt(lightThemeResourceName());
|
lightThemeColor = getThemeColor(lightThemeResourceName(), Color.WHITE);
|
||||||
}
|
}
|
||||||
return lightThemeColor;
|
return lightThemeColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getColorInt(String colorString) {
|
|
||||||
if (colorString.startsWith("#")) {
|
|
||||||
return Color.parseColor(colorString);
|
|
||||||
}
|
|
||||||
return Utils.getResourceColor(colorString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getBackgroundColor() {
|
public static int getBackgroundColor() {
|
||||||
return isDarkTheme() ? getDarkThemeColor() : getLightThemeColor();
|
return isDarkTheme() ? getDarkThemeColor() : getLightThemeColor();
|
||||||
}
|
}
|
||||||
@@ -96,6 +100,6 @@ public class ThemeHelper {
|
|||||||
? "yt_black3"
|
? "yt_black3"
|
||||||
: "yt_white1";
|
: "yt_white1";
|
||||||
|
|
||||||
return getColorInt(colorName);
|
return Utils.getColorFromString(colorName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package app.revanced.extension.youtube.patches;
|
package app.revanced.extension.youtube.patches;
|
||||||
|
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
import app.revanced.extension.youtube.shared.PlayerType;
|
||||||
import app.revanced.extension.youtube.shared.ShortsPlayerState;
|
import app.revanced.extension.youtube.shared.ShortsPlayerState;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@@ -23,7 +24,13 @@ public class BackgroundPlaybackPatch {
|
|||||||
// 7. Close the Short
|
// 7. Close the Short
|
||||||
// 8. Resume playing the regular video
|
// 8. Resume playing the regular video
|
||||||
// 9. Minimize the app (PIP should appear)
|
// 9. Minimize the app (PIP should appear)
|
||||||
return !ShortsPlayerState.isOpen();
|
if (ShortsPlayerState.isOpen()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the video player is opened and it's not playing in the feed.
|
||||||
|
PlayerType current = PlayerType.getCurrent();
|
||||||
|
return !current.isNoneOrHidden() && current != PlayerType.INLINE_MINIMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package app.revanced.extension.youtube.patches;
|
|||||||
|
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
|
||||||
/** @noinspection unused*/
|
@SuppressWarnings("unused")
|
||||||
public class DisableResumingStartupShortsPlayerPatch {
|
public class DisableResumingStartupShortsPlayerPatch {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,4 +11,11 @@ public class DisableResumingStartupShortsPlayerPatch {
|
|||||||
public static boolean disableResumingStartupShortsPlayer() {
|
public static boolean disableResumingStartupShortsPlayer() {
|
||||||
return Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
|
return Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean disableResumingStartupShortsPlayer(boolean original) {
|
||||||
|
return original && !Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,13 @@ public final class MiniplayerPatch {
|
|||||||
MODERN_2(null, 2),
|
MODERN_2(null, 2),
|
||||||
MODERN_3(null, 3),
|
MODERN_3(null, 3),
|
||||||
/**
|
/**
|
||||||
* Half broken miniplayer, that might be work in progress or left over abandoned code.
|
* Works and is functional with 20.03+
|
||||||
* Can force this type by editing the import/export settings.
|
|
||||||
*/
|
*/
|
||||||
MODERN_4(null, 4);
|
MODERN_4(null, 4),
|
||||||
|
/**
|
||||||
|
* Half broken miniplayer, and in 20.02 and earlier is declared as type 4.
|
||||||
|
*/
|
||||||
|
MODERN_5(null, 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legacy tablet hook value.
|
* Legacy tablet hook value.
|
||||||
@@ -126,12 +129,13 @@ public final class MiniplayerPatch {
|
|||||||
private static final boolean DRAG_AND_DROP_ENABLED =
|
private static final boolean DRAG_AND_DROP_ENABLED =
|
||||||
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
|
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
|
||||||
|
|
||||||
private static final boolean HIDE_EXPAND_CLOSE_ENABLED =
|
private static final boolean HIDE_OVERLAY_BUTTONS_ENABLED =
|
||||||
Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.get()
|
Settings.MINIPLAYER_HIDE_OVERLAY_BUTTONS.get()
|
||||||
&& Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.isAvailable();
|
&& Settings.MINIPLAYER_HIDE_OVERLAY_BUTTONS.isAvailable();
|
||||||
|
|
||||||
private static final boolean HIDE_SUBTEXT_ENABLED =
|
private static final boolean HIDE_SUBTEXT_ENABLED =
|
||||||
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_HIDE_SUBTEXT.get();
|
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3 || CURRENT_TYPE == MODERN_4)
|
||||||
|
&& Settings.MINIPLAYER_HIDE_SUBTEXT.get();
|
||||||
|
|
||||||
// 19.25 is last version that has forward/back buttons for phones,
|
// 19.25 is last version that has forward/back buttons for phones,
|
||||||
// but buttons still show for tablets/foldable devices and they don't work well so always hide.
|
// but buttons still show for tablets/foldable devices and they don't work well so always hide.
|
||||||
@@ -139,7 +143,7 @@ public final class MiniplayerPatch {
|
|||||||
&& (VersionCheckPatch.IS_19_34_OR_GREATER || Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get());
|
&& (VersionCheckPatch.IS_19_34_OR_GREATER || Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get());
|
||||||
|
|
||||||
private static final boolean MINIPLAYER_ROUNDED_CORNERS_ENABLED =
|
private static final boolean MINIPLAYER_ROUNDED_CORNERS_ENABLED =
|
||||||
Settings.MINIPLAYER_ROUNDED_CORNERS.get();
|
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_ROUNDED_CORNERS.get();
|
||||||
|
|
||||||
private static final boolean MINIPLAYER_HORIZONTAL_DRAG_ENABLED =
|
private static final boolean MINIPLAYER_HORIZONTAL_DRAG_ENABLED =
|
||||||
DRAG_AND_DROP_ENABLED && Settings.MINIPLAYER_HORIZONTAL_DRAG.get();
|
DRAG_AND_DROP_ENABLED && Settings.MINIPLAYER_HORIZONTAL_DRAG.get();
|
||||||
@@ -172,11 +176,12 @@ public final class MiniplayerPatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class MiniplayerHideExpandCloseAvailability implements Setting.Availability {
|
public static final class MiniplayerHideOverlayButtonsAvailability implements Setting.Availability {
|
||||||
@Override
|
@Override
|
||||||
public boolean isAvailable() {
|
public boolean isAvailable() {
|
||||||
MiniplayerType type = Settings.MINIPLAYER_TYPE.get();
|
MiniplayerType type = Settings.MINIPLAYER_TYPE.get();
|
||||||
return (!IS_19_20_OR_GREATER && (type == MODERN_1 || type == MODERN_3))
|
return type == MODERN_4
|
||||||
|
|| (!IS_19_20_OR_GREATER && (type == MODERN_1 || type == MODERN_3))
|
||||||
|| (!IS_19_26_OR_GREATER && type == MODERN_1
|
|| (!IS_19_26_OR_GREATER && type == MODERN_1
|
||||||
&& !Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get() && !Settings.MINIPLAYER_DRAG_AND_DROP.get())
|
&& !Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get() && !Settings.MINIPLAYER_DRAG_AND_DROP.get())
|
||||||
|| (IS_19_29_OR_GREATER && type == MODERN_3);
|
|| (IS_19_29_OR_GREATER && type == MODERN_3);
|
||||||
@@ -227,9 +232,13 @@ public final class MiniplayerPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static void adjustMiniplayerOpacity(ImageView view) {
|
public static void adjustMiniplayerOpacity(View view) {
|
||||||
if (CURRENT_TYPE == MODERN_1) {
|
if (CURRENT_TYPE == MODERN_1) {
|
||||||
view.setImageAlpha(OPACITY_LEVEL);
|
if (view instanceof ImageView imageView) {
|
||||||
|
imageView.setImageAlpha(OPACITY_LEVEL);
|
||||||
|
} else {
|
||||||
|
Logger.printException(() -> "Unknown miniplayer overlay view: " + view);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +256,7 @@ public final class MiniplayerPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean enableMiniplayerDoubleTapAction(boolean original) {
|
public static boolean getMiniplayerDoubleTapAction(boolean original) {
|
||||||
if (CURRENT_TYPE == DEFAULT) {
|
if (CURRENT_TYPE == DEFAULT) {
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
@@ -258,7 +267,7 @@ public final class MiniplayerPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean enableMiniplayerDragAndDrop(boolean original) {
|
public static boolean getMiniplayerDragAndDrop(boolean original) {
|
||||||
if (CURRENT_TYPE == DEFAULT) {
|
if (CURRENT_TYPE == DEFAULT) {
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
@@ -266,13 +275,36 @@ public final class MiniplayerPatch {
|
|||||||
return DRAG_AND_DROP_ENABLED;
|
return DRAG_AND_DROP_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean getRoundedCorners(boolean original) {
|
||||||
|
if (CURRENT_TYPE == DEFAULT) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MINIPLAYER_ROUNDED_CORNERS_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean setRoundedCorners(boolean original) {
|
public static boolean getHorizontalDrag(boolean original) {
|
||||||
if (CURRENT_TYPE.isModern()) {
|
if (CURRENT_TYPE == DEFAULT) {
|
||||||
return MINIPLAYER_ROUNDED_CORNERS_ENABLED;
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean getMaximizeAnimation(boolean original) {
|
||||||
|
// This must be forced on if horizontal drag is enabled,
|
||||||
|
// otherwise the UI has visual glitches when maximizing the miniplayer.
|
||||||
|
if (MINIPLAYER_HORIZONTAL_DRAG_ENABLED) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return original;
|
return original;
|
||||||
@@ -281,7 +313,7 @@ public final class MiniplayerPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static int setMiniplayerDefaultSize(int original) {
|
public static int getMiniplayerDefaultSize(int original) {
|
||||||
if (CURRENT_TYPE.isModern()) {
|
if (CURRENT_TYPE.isModern()) {
|
||||||
return MINIPLAYER_SIZE;
|
return MINIPLAYER_SIZE;
|
||||||
}
|
}
|
||||||
@@ -289,29 +321,26 @@ public final class MiniplayerPatch {
|
|||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void hideMiniplayerExpandClose(View view) {
|
||||||
|
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_OVERLAY_BUTTONS_ENABLED, view);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean setHorizontalDrag(boolean original) {
|
public static void hideMiniplayerActionButton(View view) {
|
||||||
if (CURRENT_TYPE.isModern()) {
|
if (CURRENT_TYPE == MODERN_4) {
|
||||||
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
|
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_OVERLAY_BUTTONS_ENABLED, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
return original;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static void hideMiniplayerExpandClose(ImageView view) {
|
public static void hideMiniplayerRewindForward(View view) {
|
||||||
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_EXPAND_CLOSE_ENABLED, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection point.
|
|
||||||
*/
|
|
||||||
public static void hideMiniplayerRewindForward(ImageView view) {
|
|
||||||
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_REWIND_FORWARD_ENABLED, view);
|
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_REWIND_FORWARD_ENABLED, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,16 @@ package app.revanced.extension.youtube.patches;
|
|||||||
|
|
||||||
import static app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
import static app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
import android.text.Spannable;
|
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.GuardedBy;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import app.revanced.extension.shared.Logger;
|
import app.revanced.extension.shared.Logger;
|
||||||
@@ -60,12 +56,12 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
private static volatile ReturnYouTubeDislike lastLithoShortsVideoData;
|
private static volatile ReturnYouTubeDislike lastLithoShortsVideoData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because the litho Shorts spans are created after {@link ReturnYouTubeDislikeFilterPatch}
|
* Because litho Shorts spans are created offscreen after {@link ReturnYouTubeDislikeFilterPatch}
|
||||||
* detects the video ids, after the user votes the litho will update
|
* detects the video ids, but the current Short can arbitrarily reload the same span,
|
||||||
* but {@link #lastLithoShortsVideoData} is not the correct data to use.
|
* then use the {@link #lastLithoShortsVideoData} if this value is greater than zero.
|
||||||
* If this is true, then instead use {@link #currentVideoData}.
|
|
||||||
*/
|
*/
|
||||||
private static volatile boolean lithoShortsShouldUseCurrentData;
|
@GuardedBy("ReturnYouTubeDislikePatch.class")
|
||||||
|
private static int useLithoShortsVideoDataCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last video id prefetched. Field is to prevent prefetching the same video id multiple times in a row.
|
* Last video id prefetched. Field is to prevent prefetching the same video id multiple times in a row.
|
||||||
@@ -83,12 +79,28 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
private static void clearData() {
|
private static void clearData() {
|
||||||
currentVideoData = null;
|
currentVideoData = null;
|
||||||
lastLithoShortsVideoData = null;
|
lastLithoShortsVideoData = null;
|
||||||
lithoShortsShouldUseCurrentData = false;
|
synchronized (ReturnYouTubeDislike.class) {
|
||||||
|
useLithoShortsVideoDataCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Rolling number text should not be cleared,
|
// Rolling number text should not be cleared,
|
||||||
// as it's used if incognito Short is opened/closed
|
// as it's used if incognito Short is opened/closed
|
||||||
// while a regular video is on screen.
|
// while a regular video is on screen.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If {@link #useLithoShortsVideoDataCount} was greater than zero.
|
||||||
|
*/
|
||||||
|
private static boolean decrementUseLithoDataIfNeeded() {
|
||||||
|
synchronized (ReturnYouTubeDislikePatch.class) {
|
||||||
|
if (useLithoShortsVideoDataCount > 0) {
|
||||||
|
useLithoShortsVideoDataCount--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Litho player for both regular videos and Shorts.
|
// Litho player for both regular videos and Shorts.
|
||||||
@@ -152,10 +164,13 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
return getShortsSpan(original, true);
|
return getShortsSpan(original, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversionContextString.contains("|shorts_like_button.eml")
|
if (conversionContextString.contains("|shorts_like_button.eml")) {
|
||||||
&& !Utils.containsNumber(original)) {
|
if (!Utils.containsNumber(original)) {
|
||||||
Logger.printDebug(() -> "Replacing hidden likes count");
|
Logger.printDebug(() -> "Replacing hidden likes count");
|
||||||
return getShortsSpan(original, false);
|
return getShortsSpan(original, false);
|
||||||
|
} else {
|
||||||
|
decrementUseLithoDataIfNeeded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "onLithoTextLoaded failure", ex);
|
Logger.printException(() -> "onLithoTextLoaded failure", ex);
|
||||||
@@ -170,7 +185,14 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnYouTubeDislike videoData = lastLithoShortsVideoData;
|
final ReturnYouTubeDislike videoData;
|
||||||
|
if (decrementUseLithoDataIfNeeded()) {
|
||||||
|
// New Short is loading off screen.
|
||||||
|
videoData = lastLithoShortsVideoData;
|
||||||
|
} else {
|
||||||
|
videoData = currentVideoData;
|
||||||
|
}
|
||||||
|
|
||||||
if (videoData == null) {
|
if (videoData == null) {
|
||||||
// The Shorts litho video id filter did not detect the video id.
|
// The Shorts litho video id filter did not detect the video id.
|
||||||
// This is normal in incognito mode, but otherwise is abnormal.
|
// This is normal in incognito mode, but otherwise is abnormal.
|
||||||
@@ -178,19 +200,6 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the correct dislikes data after voting.
|
|
||||||
if (lithoShortsShouldUseCurrentData) {
|
|
||||||
if (isDislikesSpan) {
|
|
||||||
lithoShortsShouldUseCurrentData = false;
|
|
||||||
}
|
|
||||||
videoData = currentVideoData;
|
|
||||||
if (videoData == null) {
|
|
||||||
Logger.printException(() -> "currentVideoData is null"); // Should never happen
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
Logger.printDebug(() -> "Using current video data for litho span");
|
|
||||||
}
|
|
||||||
|
|
||||||
return isDislikesSpan
|
return isDislikesSpan
|
||||||
? videoData.getDislikeSpanForShort((Spanned) original)
|
? videoData.getDislikeSpanForShort((Spanned) original)
|
||||||
: videoData.getLikeSpanForShort((Spanned) original);
|
: videoData.getLikeSpanForShort((Spanned) original);
|
||||||
@@ -445,7 +454,10 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
ReturnYouTubeDislike videoData = ReturnYouTubeDislike.getFetchForVideoId(videoId);
|
ReturnYouTubeDislike videoData = ReturnYouTubeDislike.getFetchForVideoId(videoId);
|
||||||
videoData.setVideoIdIsShort(true);
|
videoData.setVideoIdIsShort(true);
|
||||||
lastLithoShortsVideoData = videoData;
|
lastLithoShortsVideoData = videoData;
|
||||||
lithoShortsShouldUseCurrentData = false;
|
synchronized (ReturnYouTubeDislikePatch.class) {
|
||||||
|
// Use litho Shorts data for the next like and dislike spans.
|
||||||
|
useLithoShortsVideoDataCount = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean videoIdIsSame(@Nullable ReturnYouTubeDislike fetch, @Nullable String videoId) {
|
private static boolean videoIdIsSame(@Nullable ReturnYouTubeDislike fetch, @Nullable String videoId) {
|
||||||
@@ -480,13 +492,6 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
for (Vote v : Vote.values()) {
|
for (Vote v : Vote.values()) {
|
||||||
if (v.value == vote) {
|
if (v.value == vote) {
|
||||||
videoData.sendVote(v);
|
videoData.sendVote(v);
|
||||||
|
|
||||||
if (isNoneHiddenOrMinimized) {
|
|
||||||
if (lastLithoShortsVideoData != null) {
|
|
||||||
lithoShortsShouldUseCurrentData = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,15 @@ package app.revanced.extension.youtube.patches;
|
|||||||
import app.revanced.extension.shared.Utils;
|
import app.revanced.extension.shared.Utils;
|
||||||
|
|
||||||
public class VersionCheckPatch {
|
public class VersionCheckPatch {
|
||||||
public static final boolean IS_19_17_OR_GREATER = Utils.getAppVersionName().compareTo("19.17.00") >= 0;
|
private static boolean isVersionOrGreater(String version) {
|
||||||
public static final boolean IS_19_20_OR_GREATER = Utils.getAppVersionName().compareTo("19.20.00") >= 0;
|
return Utils.getAppVersionName().compareTo(version) >= 0;
|
||||||
public static final boolean IS_19_21_OR_GREATER = Utils.getAppVersionName().compareTo("19.21.00") >= 0;
|
}
|
||||||
public static final boolean IS_19_26_OR_GREATER = Utils.getAppVersionName().compareTo("19.26.00") >= 0;
|
|
||||||
public static final boolean IS_19_29_OR_GREATER = Utils.getAppVersionName().compareTo("19.29.00") >= 0;
|
public static final boolean IS_19_17_OR_GREATER = isVersionOrGreater("19.17.00");
|
||||||
public static final boolean IS_19_34_OR_GREATER = Utils.getAppVersionName().compareTo("19.34.00") >= 0;
|
public static final boolean IS_19_20_OR_GREATER = isVersionOrGreater("19.20.00");
|
||||||
public static final boolean IS_19_46_OR_GREATER = Utils.getAppVersionName().compareTo("19.46.00") >= 0;
|
public static final boolean IS_19_21_OR_GREATER = isVersionOrGreater("19.21.00");
|
||||||
|
public static final boolean IS_19_26_OR_GREATER = isVersionOrGreater("19.26.00");
|
||||||
|
public static final boolean IS_19_29_OR_GREATER = isVersionOrGreater("19.29.00");
|
||||||
|
public static final boolean IS_19_34_OR_GREATER = isVersionOrGreater("19.34.00");
|
||||||
|
public static final boolean IS_19_46_OR_GREATER = isVersionOrGreater("19.46.00");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ final class CommentsFilter extends Filter {
|
|||||||
|
|
||||||
private final StringFilterGroup commentComposer;
|
private final StringFilterGroup commentComposer;
|
||||||
private final ByteArrayFilterGroup emojiPickerBufferGroup;
|
private final ByteArrayFilterGroup emojiPickerBufferGroup;
|
||||||
|
private final StringFilterGroup filterChipBar;
|
||||||
|
private final ByteArrayFilterGroup aiCommentsSummary;
|
||||||
|
|
||||||
public CommentsFilter() {
|
public CommentsFilter() {
|
||||||
var chatSummary = new StringFilterGroup(
|
var chatSummary = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMENTS_CHAT_SUMMARY,
|
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
|
||||||
"live_chat_summary_banner.eml"
|
"live_chat_summary_banner.eml"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -58,6 +60,16 @@ final class CommentsFilter extends Filter {
|
|||||||
"id.comment.quick_emoji.button"
|
"id.comment.quick_emoji.button"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
filterChipBar = new StringFilterGroup(
|
||||||
|
Settings.HIDE_COMMENTS_AI_SUMMARY,
|
||||||
|
"filter_chip_bar.eml"
|
||||||
|
);
|
||||||
|
|
||||||
|
aiCommentsSummary = new ByteArrayFilterGroup(
|
||||||
|
null,
|
||||||
|
"yt_fill_spark_"
|
||||||
|
);
|
||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
chatSummary,
|
chatSummary,
|
||||||
commentsByMembers,
|
commentsByMembers,
|
||||||
@@ -65,7 +77,8 @@ final class CommentsFilter extends Filter {
|
|||||||
createAShort,
|
createAShort,
|
||||||
previewComment,
|
previewComment,
|
||||||
thanksButton,
|
thanksButton,
|
||||||
commentComposer
|
commentComposer,
|
||||||
|
filterChipBar
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +97,13 @@ final class CommentsFilter extends Filter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (matchedGroup == filterChipBar) {
|
||||||
|
if (aiCommentsSummary.check(protobufBufferArray).isFiltered()) {
|
||||||
|
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
|
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ final class DescriptionComponentsFilter extends Filter {
|
|||||||
"metadata"
|
"metadata"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final StringFilterGroup aiGeneratedVideoSummarySection = new StringFilterGroup(
|
||||||
|
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
|
||||||
|
"cell_expandable_metadata.eml"
|
||||||
|
);
|
||||||
|
|
||||||
final StringFilterGroup attributesSection = new StringFilterGroup(
|
final StringFilterGroup attributesSection = new StringFilterGroup(
|
||||||
Settings.HIDE_ATTRIBUTES_SECTION,
|
Settings.HIDE_ATTRIBUTES_SECTION,
|
||||||
"gaming_section",
|
"gaming_section",
|
||||||
@@ -67,6 +72,7 @@ final class DescriptionComponentsFilter extends Filter {
|
|||||||
);
|
);
|
||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
|
aiGeneratedVideoSummarySection,
|
||||||
attributesSection,
|
attributesSection,
|
||||||
infoCardsSection,
|
infoCardsSection,
|
||||||
howThisWasMadeSection,
|
howThisWasMadeSection,
|
||||||
|
|||||||
@@ -454,16 +454,20 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hideShelves() {
|
private static boolean hideShelves() {
|
||||||
// If the player is opened while library is selected,
|
// Horizontal shelves are used for music/game links in video descriptions,
|
||||||
// then filter any recommendations below the player.
|
// such as https://youtube.com/watch?v=W8kI1na3S2M
|
||||||
if (PlayerType.getCurrent().isMaximizedOrFullscreen()
|
if (PlayerType.getCurrent().isMaximizedOrFullscreen()) {
|
||||||
// Or if the search is active while library is selected, then also filter.
|
return false;
|
||||||
|| NavigationBar.isSearchBarActive()) {
|
}
|
||||||
|
|
||||||
|
// Must check search bar after player type, since search results
|
||||||
|
// can be in the background behind an open player.
|
||||||
|
if (NavigationBar.isSearchBarActive()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not hide if the navigation back button is visible,
|
// Do not hide if the navigation back button is visible,
|
||||||
// otherwise the content shelves in the YouTube Movie/Courses pages is hidden.
|
// otherwise the content shelves in the explore/music/courses pages are hidde.
|
||||||
if (NavigationBar.isBackButtonVisible()) {
|
if (NavigationBar.isBackButtonVisible()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,25 @@ package app.revanced.extension.youtube.patches.components;
|
|||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.settings.Setting;
|
||||||
|
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
import app.revanced.extension.youtube.shared.PlayerType;
|
import app.revanced.extension.youtube.shared.PlayerType;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class PlayerFlyoutMenuItemsFilter extends Filter {
|
public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||||
|
|
||||||
|
public static final class HideAudioFlyoutMenuAvailability implements Setting.Availability {
|
||||||
|
private static final boolean AVAILABLE_ON_LAUNCH = SpoofVideoStreamsPatch.notSpoofingToAndroid();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
// Check conditions of launch and now. Otherwise if spoofing is changed
|
||||||
|
// without a restart the setting will show as available when it's not.
|
||||||
|
return AVAILABLE_ON_LAUNCH && SpoofVideoStreamsPatch.notSpoofingToAndroid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final ByteArrayFilterGroupList flyoutFilterGroupList = new ByteArrayFilterGroupList();
|
private final ByteArrayFilterGroupList flyoutFilterGroupList = new ByteArrayFilterGroupList();
|
||||||
|
|
||||||
private final ByteArrayFilterGroup exception;
|
private final ByteArrayFilterGroup exception;
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ public final class SeekbarColorPatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String loadRawResourceAsString(int resourceId) {
|
private static String loadRawResourceAsString(int resourceId) {
|
||||||
|
//noinspection CharsetObjectCanBeUsed
|
||||||
try (InputStream inputStream = Utils.getContext().getResources().openRawResource(resourceId);
|
try (InputStream inputStream = Utils.getContext().getResources().openRawResource(resourceId);
|
||||||
Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
|
Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
|
||||||
return scanner.next();
|
return scanner.next();
|
||||||
@@ -281,6 +282,20 @@ public final class SeekbarColorPatch {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
|
* 19.49+
|
||||||
|
*/
|
||||||
|
public static int[] getPlayerLinearGradient(int[] original, int x0, int y1) {
|
||||||
|
// This hook is used for both the player and the feed.
|
||||||
|
// Feed usage always has x0 and y1 value of zero, and the player is always non zero.
|
||||||
|
if (HIDE_SEEKBAR_THUMBNAIL_ENABLED && x0 == 0 && y1 == 0) {
|
||||||
|
return HIDDEN_SEEKBAR_GRADIENT_COLORS;
|
||||||
|
}
|
||||||
|
return getPlayerLinearGradient(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
* Pre 19.49
|
||||||
*/
|
*/
|
||||||
public static int[] getPlayerLinearGradient(int[] original) {
|
public static int[] getPlayerLinearGradient(int[] original) {
|
||||||
return SEEKBAR_CUSTOM_COLOR_ENABLED
|
return SEEKBAR_CUSTOM_COLOR_ENABLED
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public class ReturnYouTubeDislike {
|
|||||||
private static final Rect middleSeparatorBounds;
|
private static final Rect middleSeparatorBounds;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Left separator horizontal padding for Rolling Number layout.
|
* Horizontal padding between the left and middle separator.
|
||||||
*/
|
*/
|
||||||
public static final int leftSeparatorShapePaddingPixels;
|
public static final int leftSeparatorShapePaddingPixels;
|
||||||
private static final ShapeDrawable leftSeparatorShape;
|
private static final ShapeDrawable leftSeparatorShape;
|
||||||
@@ -129,7 +129,7 @@ public class ReturnYouTubeDislike {
|
|||||||
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp);
|
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp);
|
||||||
middleSeparatorBounds = new Rect(0, 0, middleSeparatorSize, middleSeparatorSize);
|
middleSeparatorBounds = new Rect(0, 0, middleSeparatorSize, middleSeparatorSize);
|
||||||
|
|
||||||
leftSeparatorShapePaddingPixels = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10.0f, dp);
|
leftSeparatorShapePaddingPixels = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8.4f, dp);
|
||||||
|
|
||||||
leftSeparatorShape = new ShapeDrawable(new RectShape());
|
leftSeparatorShape = new ShapeDrawable(new RectShape());
|
||||||
leftSeparatorShape.setBounds(leftSeparatorBounds);
|
leftSeparatorShape.setBounds(leftSeparatorBounds);
|
||||||
@@ -238,7 +238,7 @@ public class ReturnYouTubeDislike {
|
|||||||
String leftSeparatorString = getTextDirectionString();
|
String leftSeparatorString = getTextDirectionString();
|
||||||
final Spannable leftSeparatorSpan;
|
final Spannable leftSeparatorSpan;
|
||||||
if (isRollingNumber) {
|
if (isRollingNumber) {
|
||||||
leftSeparatorSpan = new SpannableString(leftSeparatorString);
|
leftSeparatorSpan = new SpannableString(leftSeparatorString);
|
||||||
} else {
|
} else {
|
||||||
leftSeparatorString += " ";
|
leftSeparatorString += " ";
|
||||||
leftSeparatorSpan = new SpannableString(leftSeparatorString);
|
leftSeparatorSpan = new SpannableString(leftSeparatorString);
|
||||||
@@ -623,7 +623,7 @@ public class ReturnYouTubeDislike {
|
|||||||
userVote = vote;
|
userVote = vote;
|
||||||
clearUICache();
|
clearUICache();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (future.isDone()) {
|
if (future.isDone()) {
|
||||||
// Update the fetched vote data.
|
// Update the fetched vote data.
|
||||||
RYDVoteData voteData = getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH);
|
RYDVoteData voteData = getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import static app.revanced.extension.youtube.patches.ChangeFormFactorPatch.FormF
|
|||||||
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
|
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
|
||||||
import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode;
|
import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode;
|
||||||
import static app.revanced.extension.youtube.patches.ForceOriginalAudioPatch.ForceOriginalAudioAvailability;
|
import static app.revanced.extension.youtube.patches.ForceOriginalAudioPatch.ForceOriginalAudioAvailability;
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideExpandCloseAvailability;
|
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
|
||||||
@@ -20,6 +19,7 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerT
|
|||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_4;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_4;
|
||||||
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
|
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
|
||||||
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
||||||
|
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
|
||||||
@@ -40,6 +40,7 @@ import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrow
|
|||||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
|
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
|
||||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
|
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
|
||||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime;
|
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime;
|
||||||
|
import app.revanced.extension.youtube.patches.MiniplayerPatch;
|
||||||
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
|
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
|
||||||
|
|
||||||
public class Settings extends BaseSettings {
|
public class Settings extends BaseSettings {
|
||||||
@@ -156,7 +157,7 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN);
|
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN);
|
||||||
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN);
|
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN);
|
||||||
public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerHorizontalDragAvailability());
|
public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerHorizontalDragAvailability());
|
||||||
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", FALSE, true, new MiniplayerHideExpandCloseAvailability());
|
public static final BooleanSetting MINIPLAYER_HIDE_OVERLAY_BUTTONS = new BooleanSetting("revanced_miniplayer_hide_overlay_buttons", FALSE, true, new MiniplayerPatch.MiniplayerHideOverlayButtonsAvailability());
|
||||||
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
|
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
|
||||||
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", TRUE, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", TRUE, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
||||||
public static final BooleanSetting MINIPLAYER_ROUNDED_CORNERS = new BooleanSetting("revanced_miniplayer_rounded_corners", TRUE, true, MINIPLAYER_ANY_MODERN);
|
public static final BooleanSetting MINIPLAYER_ROUNDED_CORNERS = new BooleanSetting("revanced_miniplayer_rounded_corners", TRUE, true, MINIPLAYER_ANY_MODERN);
|
||||||
@@ -168,7 +169,8 @@ public class Settings extends BaseSettings {
|
|||||||
public static final StringSetting EXTERNAL_DOWNLOADER_PACKAGE_NAME = new StringSetting("revanced_external_downloader_name",
|
public static final StringSetting EXTERNAL_DOWNLOADER_PACKAGE_NAME = new StringSetting("revanced_external_downloader_name",
|
||||||
"org.schabi.newpipe" /* NewPipe */, parentsAny(EXTERNAL_DOWNLOADER, EXTERNAL_DOWNLOADER_ACTION_BUTTON));
|
"org.schabi.newpipe" /* NewPipe */, parentsAny(EXTERNAL_DOWNLOADER, EXTERNAL_DOWNLOADER_ACTION_BUTTON));
|
||||||
// Comments
|
// Comments
|
||||||
public static final BooleanSetting HIDE_COMMENTS_CHAT_SUMMARY = new BooleanSetting("revanced_hide_comments_chat_summary", FALSE);
|
public static final BooleanSetting HIDE_COMMENTS_AI_CHAT_SUMMARY = new BooleanSetting("revanced_hide_comments_ai_chat_summary", FALSE);
|
||||||
|
public static final BooleanSetting HIDE_COMMENTS_AI_SUMMARY = new BooleanSetting("revanced_hide_comments_ai_summary", FALSE);
|
||||||
public static final BooleanSetting HIDE_COMMENTS_BY_MEMBERS_HEADER = new BooleanSetting("revanced_hide_comments_by_members_header", FALSE);
|
public static final BooleanSetting HIDE_COMMENTS_BY_MEMBERS_HEADER = new BooleanSetting("revanced_hide_comments_by_members_header", FALSE);
|
||||||
public static final BooleanSetting HIDE_COMMENTS_CREATE_A_SHORT_BUTTON = new BooleanSetting("revanced_hide_comments_create_a_short_button", TRUE);
|
public static final BooleanSetting HIDE_COMMENTS_CREATE_A_SHORT_BUTTON = new BooleanSetting("revanced_hide_comments_create_a_short_button", TRUE);
|
||||||
public static final BooleanSetting HIDE_COMMENTS_TIMESTAMP_AND_EMOJI_BUTTONS = new BooleanSetting("revanced_hide_comments_timestamp_and_emoji_buttons", TRUE);
|
public static final BooleanSetting HIDE_COMMENTS_TIMESTAMP_AND_EMOJI_BUTTONS = new BooleanSetting("revanced_hide_comments_timestamp_and_emoji_buttons", TRUE);
|
||||||
@@ -176,6 +178,7 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting HIDE_COMMENTS_SECTION = new BooleanSetting("revanced_hide_comments_section", FALSE);
|
public static final BooleanSetting HIDE_COMMENTS_SECTION = new BooleanSetting("revanced_hide_comments_section", FALSE);
|
||||||
public static final BooleanSetting HIDE_COMMENTS_THANKS_BUTTON = new BooleanSetting("revanced_hide_comments_thanks_button", TRUE);
|
public static final BooleanSetting HIDE_COMMENTS_THANKS_BUTTON = new BooleanSetting("revanced_hide_comments_thanks_button", TRUE);
|
||||||
// Description
|
// Description
|
||||||
|
public static final BooleanSetting HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION = new BooleanSetting("revanced_hide_ai_generated_video_summary_section", FALSE);
|
||||||
public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE);
|
public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE);
|
||||||
public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE);
|
public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE);
|
||||||
public static final BooleanSetting HIDE_HOW_THIS_WAS_MADE_SECTION = new BooleanSetting("revanced_hide_how_this_was_made_section", FALSE);
|
public static final BooleanSetting HIDE_HOW_THIS_WAS_MADE_SECTION = new BooleanSetting("revanced_hide_how_this_was_made_section", FALSE);
|
||||||
@@ -196,7 +199,7 @@ public class Settings extends BaseSettings {
|
|||||||
// Player flyout menu items
|
// Player flyout menu items
|
||||||
public static final BooleanSetting HIDE_PLAYER_FLYOUT_ADDITIONAL_SETTINGS = new BooleanSetting("revanced_hide_player_flyout_additional_settings", FALSE);
|
public static final BooleanSetting HIDE_PLAYER_FLYOUT_ADDITIONAL_SETTINGS = new BooleanSetting("revanced_hide_player_flyout_additional_settings", FALSE);
|
||||||
public static final BooleanSetting HIDE_PLAYER_FLYOUT_AMBIENT_MODE = new BooleanSetting("revanced_hide_player_flyout_ambient_mode", FALSE);
|
public static final BooleanSetting HIDE_PLAYER_FLYOUT_AMBIENT_MODE = new BooleanSetting("revanced_hide_player_flyout_ambient_mode", FALSE);
|
||||||
public static final BooleanSetting HIDE_PLAYER_FLYOUT_AUDIO_TRACK = new BooleanSetting("revanced_hide_player_flyout_audio_track", FALSE);
|
public static final BooleanSetting HIDE_PLAYER_FLYOUT_AUDIO_TRACK = new BooleanSetting("revanced_hide_player_flyout_audio_track", FALSE, new HideAudioFlyoutMenuAvailability());
|
||||||
public static final BooleanSetting HIDE_PLAYER_FLYOUT_CAPTIONS = new BooleanSetting("revanced_hide_player_flyout_captions", FALSE);
|
public static final BooleanSetting HIDE_PLAYER_FLYOUT_CAPTIONS = new BooleanSetting("revanced_hide_player_flyout_captions", FALSE);
|
||||||
public static final BooleanSetting HIDE_PLAYER_FLYOUT_HELP = new BooleanSetting("revanced_hide_player_flyout_help", TRUE);
|
public static final BooleanSetting HIDE_PLAYER_FLYOUT_HELP = new BooleanSetting("revanced_hide_player_flyout_help", TRUE);
|
||||||
public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOCK_SCREEN = new BooleanSetting("revanced_hide_player_flyout_lock_screen", FALSE);
|
public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOCK_SCREEN = new BooleanSetting("revanced_hide_player_flyout_lock_screen", FALSE);
|
||||||
@@ -218,7 +221,7 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");
|
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");
|
||||||
public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true);
|
public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true);
|
||||||
public static final EnumSetting<StartPage> CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.DEFAULT, true);
|
public static final EnumSetting<StartPage> CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.DEFAULT, true);
|
||||||
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "19.26.42", true, parent(SPOOF_APP_VERSION));
|
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "19.01.34", true, parent(SPOOF_APP_VERSION));
|
||||||
// Custom filter
|
// Custom filter
|
||||||
public static final BooleanSetting CUSTOM_FILTER = new BooleanSetting("revanced_custom_filter", FALSE);
|
public static final BooleanSetting CUSTOM_FILTER = new BooleanSetting("revanced_custom_filter", FALSE);
|
||||||
public static final StringSetting CUSTOM_FILTER_STRINGS = new StringSetting("revanced_custom_filter_strings", "", true, parent(CUSTOM_FILTER));
|
public static final StringSetting CUSTOM_FILTER_STRINGS = new StringSetting("revanced_custom_filter_strings", "", true, parent(CUSTOM_FILTER));
|
||||||
@@ -231,7 +234,8 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting HIDE_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_hide_notifications_button", FALSE, true);
|
public static final BooleanSetting HIDE_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_hide_notifications_button", FALSE, true);
|
||||||
public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true,
|
public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true,
|
||||||
"revanced_switch_create_with_notifications_button_user_dialog_message");
|
"revanced_switch_create_with_notifications_button_user_dialog_message");
|
||||||
public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", FALSE, true);
|
public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", FALSE, true,
|
||||||
|
"revanced_disable_translucent_status_bar_user_dialog_message");
|
||||||
public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT = new BooleanSetting("revanced_disable_translucent_navigation_bar_light", FALSE, true);
|
public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT = new BooleanSetting("revanced_disable_translucent_navigation_bar_light", FALSE, true);
|
||||||
public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK = new BooleanSetting("revanced_disable_translucent_navigation_bar_dark", FALSE, true);
|
public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK = new BooleanSetting("revanced_disable_translucent_navigation_bar_dark", FALSE, true);
|
||||||
|
|
||||||
@@ -315,6 +319,7 @@ public class Settings extends BaseSettings {
|
|||||||
parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME));
|
parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME));
|
||||||
public static final IntegerSetting SWIPE_MAGNITUDE_THRESHOLD = new IntegerSetting("revanced_swipe_threshold", 30, true,
|
public static final IntegerSetting SWIPE_MAGNITUDE_THRESHOLD = new IntegerSetting("revanced_swipe_threshold", 30, true,
|
||||||
parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME));
|
parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME));
|
||||||
|
public static final IntegerSetting SWIPE_VOLUME_SENSITIVITY = new IntegerSetting("revanced_swipe_volume_sensitivity", 1, true, parent(SWIPE_VOLUME));
|
||||||
public static final BooleanSetting SWIPE_SHOW_CIRCULAR_OVERLAY = new BooleanSetting("revanced_swipe_show_circular_overlay", FALSE, true,
|
public static final BooleanSetting SWIPE_SHOW_CIRCULAR_OVERLAY = new BooleanSetting("revanced_swipe_show_circular_overlay", FALSE, true,
|
||||||
parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME));
|
parentsAny(SWIPE_BRIGHTNESS, SWIPE_VOLUME));
|
||||||
public static final BooleanSetting SWIPE_OVERLAY_MINIMAL_STYLE = new BooleanSetting("revanced_swipe_overlay_minimal_style", FALSE, true,
|
public static final BooleanSetting SWIPE_OVERLAY_MINIMAL_STYLE = new BooleanSetting("revanced_swipe_overlay_minimal_style", FALSE, true,
|
||||||
@@ -446,7 +451,7 @@ public class Settings extends BaseSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Old spoof versions that no longer work.
|
// Old spoof versions that no longer work.
|
||||||
if (SPOOF_APP_VERSION_TARGET.get().compareTo("19.00.00") < 0) {
|
if (SPOOF_APP_VERSION_TARGET.get().compareTo(SPOOF_APP_VERSION_TARGET.defaultValue) < 0) {
|
||||||
Logger.printInfo(() -> "Resetting spoof app version target");
|
Logger.printInfo(() -> "Resetting spoof app version target");
|
||||||
SPOOF_APP_VERSION_TARGET.resetToDefault();
|
SPOOF_APP_VERSION_TARGET.resetToDefault();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package app.revanced.extension.youtube.settings.preference;
|
||||||
|
|
||||||
|
import static app.revanced.extension.shared.StringRef.str;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.preference.SwitchPreference;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||||
|
|
||||||
|
@SuppressWarnings({"deprecation", "unused"})
|
||||||
|
public class HideAudioFlyoutMenuPreference extends SwitchPreference {
|
||||||
|
|
||||||
|
{
|
||||||
|
// Audio menu is not available if spoofing to Android client type.
|
||||||
|
if (!SpoofVideoStreamsPatch.notSpoofingToAndroid()) {
|
||||||
|
String summary = str("revanced_hide_player_flyout_audio_track_not_available");
|
||||||
|
setSummary(summary);
|
||||||
|
setSummaryOn(summary);
|
||||||
|
setSummaryOff(summary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HideAudioFlyoutMenuPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
public HideAudioFlyoutMenuPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
public HideAudioFlyoutMenuPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
public HideAudioFlyoutMenuPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,6 @@ import android.widget.Toolbar;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import app.revanced.extension.shared.Logger;
|
import app.revanced.extension.shared.Logger;
|
||||||
import app.revanced.extension.shared.Utils;
|
import app.revanced.extension.shared.Utils;
|
||||||
@@ -139,11 +138,13 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
|
|||||||
.findViewById(android.R.id.content)
|
.findViewById(android.R.id.content)
|
||||||
.getParent();
|
.getParent();
|
||||||
|
|
||||||
// Fix required for Android 15 and YT 19.45+
|
// Fix edge-to-edge screen with Android 15 and YT 19.45+
|
||||||
|
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
|
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||||
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
|
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
|
||||||
v.setPadding(0, statusInsets.top, 0, 0);
|
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
|
||||||
|
v.setPadding(0, statusInsets.top, 0, navInsets.bottom);
|
||||||
return insets;
|
return insets;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package app.revanced.extension.youtube.swipecontrols
|
package app.revanced.extension.youtube.swipecontrols
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import app.revanced.extension.shared.StringRef.str
|
import app.revanced.extension.shared.StringRef.str
|
||||||
import app.revanced.extension.shared.Utils
|
import app.revanced.extension.shared.Utils
|
||||||
@@ -9,12 +8,8 @@ import app.revanced.extension.youtube.shared.PlayerType
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* provider for configuration for volume and brightness swipe controls
|
* provider for configuration for volume and brightness swipe controls
|
||||||
*
|
|
||||||
* @param context the context to create in
|
|
||||||
*/
|
*/
|
||||||
class SwipeControlsConfigurationProvider(
|
class SwipeControlsConfigurationProvider {
|
||||||
private val context: Context,
|
|
||||||
) {
|
|
||||||
//region swipe enable
|
//region swipe enable
|
||||||
/**
|
/**
|
||||||
* should swipe controls be enabled? (global setting)
|
* should swipe controls be enabled? (global setting)
|
||||||
@@ -60,6 +55,23 @@ class SwipeControlsConfigurationProvider(
|
|||||||
*/
|
*/
|
||||||
val swipeMagnitudeThreshold: Int
|
val swipeMagnitudeThreshold: Int
|
||||||
get() = Settings.SWIPE_MAGNITUDE_THRESHOLD.get()
|
get() = Settings.SWIPE_MAGNITUDE_THRESHOLD.get()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How much volume will change by single swipe.
|
||||||
|
* If it is set to 0, it will reset to the default value because 0 would disable swiping.
|
||||||
|
* */
|
||||||
|
val volumeSwipeSensitivity: Int
|
||||||
|
get() {
|
||||||
|
val sensitivity = Settings.SWIPE_VOLUME_SENSITIVITY.get()
|
||||||
|
|
||||||
|
if (sensitivity < 1) {
|
||||||
|
Settings.SWIPE_VOLUME_SENSITIVITY.resetToDefault()
|
||||||
|
|
||||||
|
return Settings.SWIPE_VOLUME_SENSITIVITY.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
return sensitivity
|
||||||
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
//region overlay adjustments
|
//region overlay adjustments
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class SwipeControlsHostActivity : Activity() {
|
|||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
// create controllers
|
// create controllers
|
||||||
printDebug { "initializing swipe controls controllers" }
|
printDebug { "initializing swipe controls controllers" }
|
||||||
config = SwipeControlsConfigurationProvider(this)
|
config = SwipeControlsConfigurationProvider()
|
||||||
keys = VolumeKeysController(this)
|
keys = VolumeKeysController(this)
|
||||||
audio = createAudioController()
|
audio = createAudioController()
|
||||||
screen = createScreenController()
|
screen = createScreenController()
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class VolumeKeysController(
|
|||||||
private fun handleVolumeKeyEvent(event: KeyEvent, volumeUp: Boolean): Boolean {
|
private fun handleVolumeKeyEvent(event: KeyEvent, volumeUp: Boolean): Boolean {
|
||||||
if (event.action == KeyEvent.ACTION_DOWN) {
|
if (event.action == KeyEvent.ACTION_DOWN) {
|
||||||
controller.audio?.apply {
|
controller.audio?.apply {
|
||||||
volume += if (volumeUp) 1 else -1
|
volume += controller.config.volumeSwipeSensitivity * if (volumeUp) 1 else -1
|
||||||
controller.overlay.onVolumeChanged(volume, maxVolume)
|
controller.overlay.onVolumeChanged(volume, maxVolume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ abstract class BaseGestureController(
|
|||||||
controller.overlay,
|
controller.overlay,
|
||||||
10,
|
10,
|
||||||
1,
|
1,
|
||||||
|
controller.config.volumeSwipeSensitivity,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ interface VolumeAndBrightnessScroller {
|
|||||||
* @param overlayController overlay controller instance
|
* @param overlayController overlay controller instance
|
||||||
* @param volumeDistance unit distance for volume scrolling, in dp
|
* @param volumeDistance unit distance for volume scrolling, in dp
|
||||||
* @param brightnessDistance unit distance for brightness scrolling, in dp
|
* @param brightnessDistance unit distance for brightness scrolling, in dp
|
||||||
|
* @param volumeSwipeSensitivity how much volume will change by single swipe
|
||||||
*/
|
*/
|
||||||
class VolumeAndBrightnessScrollerImpl(
|
class VolumeAndBrightnessScrollerImpl(
|
||||||
context: Context,
|
context: Context,
|
||||||
@@ -49,6 +50,7 @@ class VolumeAndBrightnessScrollerImpl(
|
|||||||
private val overlayController: SwipeControlsOverlay,
|
private val overlayController: SwipeControlsOverlay,
|
||||||
volumeDistance: Int = 10,
|
volumeDistance: Int = 10,
|
||||||
brightnessDistance: Int = 1,
|
brightnessDistance: Int = 1,
|
||||||
|
private val volumeSwipeSensitivity: Int,
|
||||||
) : VolumeAndBrightnessScroller {
|
) : VolumeAndBrightnessScroller {
|
||||||
|
|
||||||
// region volume
|
// region volume
|
||||||
@@ -60,7 +62,7 @@ class VolumeAndBrightnessScrollerImpl(
|
|||||||
),
|
),
|
||||||
) { _, _, direction ->
|
) { _, _, direction ->
|
||||||
volumeController?.run {
|
volumeController?.run {
|
||||||
volume += direction
|
volume += direction * volumeSwipeSensitivity
|
||||||
overlayController.onVolumeChanged(volume, maxVolume)
|
overlayController.onVolumeChanged(volume, maxVolume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class SwipeControlsOverlayLayout(
|
|||||||
private val config: SwipeControlsConfigurationProvider,
|
private val config: SwipeControlsConfigurationProvider,
|
||||||
) : RelativeLayout(context), SwipeControlsOverlay {
|
) : RelativeLayout(context), SwipeControlsOverlay {
|
||||||
|
|
||||||
constructor(context: Context) : this(context, SwipeControlsConfigurationProvider(context))
|
constructor(context: Context) : this(context, SwipeControlsConfigurationProvider())
|
||||||
|
|
||||||
// Drawable icons for brightness and volume
|
// Drawable icons for brightness and volume
|
||||||
private val autoBrightnessIcon: Drawable = getDrawable("revanced_ic_sc_brightness_auto")
|
private val autoBrightnessIcon: Drawable = getDrawable("revanced_ic_sc_brightness_auto")
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
android.useAndroidX = true
|
android.useAndroidX = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 5.15.0-dev.3
|
version = 5.20.0-dev.5
|
||||||
|
|||||||
@@ -108,6 +108,10 @@ public final class app/revanced/patches/all/misc/shortcut/sharetargets/RemoveSha
|
|||||||
public static final fun getRemoveShareTargetsPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
public static final fun getRemoveShareTargetsPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34Kt {
|
||||||
|
public static final fun getSetTargetSdkVersion34 ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract interface class app/revanced/patches/all/misc/transformation/IMethodCall {
|
public abstract interface class app/revanced/patches/all/misc/transformation/IMethodCall {
|
||||||
public abstract fun getDefinedClassName ()Ljava/lang/String;
|
public abstract fun getDefinedClassName ()Ljava/lang/String;
|
||||||
public abstract fun getMethodName ()Ljava/lang/String;
|
public abstract fun getMethodName ()Ljava/lang/String;
|
||||||
@@ -132,6 +136,10 @@ public final class app/revanced/patches/amazon/DeepLinkingPatchKt {
|
|||||||
public static final fun getDeepLinkingPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getDeepLinkingPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/angulus/ads/RemoveAdsPatchKt {
|
||||||
|
public static final fun getAngulusPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/backdrops/misc/pro/ProUnlockPatchKt {
|
public final class app/revanced/patches/backdrops/misc/pro/ProUnlockPatchKt {
|
||||||
public static final fun getProUnlockPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getProUnlockPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -268,6 +276,10 @@ public final class app/revanced/patches/messenger/inputfield/DisableTypingIndica
|
|||||||
public static final fun getDisableTypingIndicatorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getDisableTypingIndicatorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/messenger/navbar/RemoveMetaAITabPatchKt {
|
||||||
|
public static final fun getRemoveMetaAITabPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatchKt {
|
public final class app/revanced/patches/mifitness/misc/locale/ForceEnglishLocalePatchKt {
|
||||||
public static final fun getForceEnglishLocalePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getForceEnglishLocalePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -396,6 +408,10 @@ public final class app/revanced/patches/pixiv/ads/HideAdsPatchKt {
|
|||||||
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/protonmail/signature/RemoveSentFromSignaturePatchKt {
|
||||||
|
public static final fun getRemoveSentFromSignaturePatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/rar/misc/annoyances/purchasereminder/HidePurchaseReminderPatchKt {
|
public final class app/revanced/patches/rar/misc/annoyances/purchasereminder/HidePurchaseReminderPatchKt {
|
||||||
public static final fun getHidePurchaseReminderPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHidePurchaseReminderPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -556,7 +572,9 @@ public final class app/revanced/patches/shared/misc/extension/ExtensionHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/extension/SharedExtensionPatchKt {
|
public final class app/revanced/patches/shared/misc/extension/SharedExtensionPatchKt {
|
||||||
|
public static final fun extensionHook (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lapp/revanced/patcher/Fingerprint;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook;
|
||||||
public static final fun extensionHook (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook;
|
public static final fun extensionHook (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook;
|
||||||
|
public static synthetic fun extensionHook$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lapp/revanced/patcher/Fingerprint;ILjava/lang/Object;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook;
|
||||||
public static synthetic fun extensionHook$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook;
|
public static synthetic fun extensionHook$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patches/shared/misc/extension/ExtensionHook;
|
||||||
public static final fun sharedExtensionPatch (Ljava/lang/String;[Lapp/revanced/patches/shared/misc/extension/ExtensionHook;)Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun sharedExtensionPatch (Ljava/lang/String;[Lapp/revanced/patches/shared/misc/extension/ExtensionHook;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
public static final fun sharedExtensionPatch ([Lapp/revanced/patches/shared/misc/extension/ExtensionHook;)Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun sharedExtensionPatch ([Lapp/revanced/patches/shared/misc/extension/ExtensionHook;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
@@ -776,8 +794,8 @@ public final class app/revanced/patches/shared/misc/settings/preference/TextPref
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatchKt {
|
public final class app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatchKt {
|
||||||
public static final fun spoofVideoStreamsPatch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun spoofVideoStreamsPatch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
public static synthetic fun spoofVideoStreamsPatch$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch;
|
public static synthetic fun spoofVideoStreamsPatch$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatchKt {
|
public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatchKt {
|
||||||
@@ -816,6 +834,14 @@ public final class app/revanced/patches/spotify/lite/ondemand/OnDemandPatchKt {
|
|||||||
public static final fun getOnDemandPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getOnDemandPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/spotify/misc/UnlockPremiumPatchKt {
|
||||||
|
public static final fun getUnlockPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/spotify/misc/extension/ExtensionPatchKt {
|
||||||
|
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/spotify/misc/fix/SpoofSignaturePatchKt {
|
public final class app/revanced/patches/spotify/misc/fix/SpoofSignaturePatchKt {
|
||||||
public static final fun getSpoofSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSpoofSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -1088,6 +1114,14 @@ public final class app/revanced/patches/youtube/interaction/seekbar/EnableSlideT
|
|||||||
public static final fun getEnableSlideToSeekPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getEnableSlideToSeekPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/youtube/interaction/seekbar/HideSeekbarPatchKt {
|
||||||
|
public static final fun getHideSeekbarPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/youtube/interaction/seekbar/SeekbarPatchKt {
|
||||||
|
public static final fun getSeekbarPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/interaction/seekbar/SeekbarThumbnailsPatchKt {
|
public final class app/revanced/patches/youtube/interaction/seekbar/SeekbarThumbnailsPatchKt {
|
||||||
public static final fun getSeekbarThumbnailsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSeekbarThumbnailsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -1177,17 +1211,7 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatchKt {
|
public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatchKt {
|
||||||
public static final fun getFloatyBarButtonTopMargin ()J
|
|
||||||
public static final fun getMiniplayerMaxSize ()J
|
|
||||||
public static final fun getMiniplayerPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getMiniplayerPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
public static final fun getModernMiniplayerClose ()J
|
|
||||||
public static final fun getModernMiniplayerExpand ()J
|
|
||||||
public static final fun getModernMiniplayerForwardButton ()J
|
|
||||||
public static final fun getModernMiniplayerRewindButton ()J
|
|
||||||
public static final fun getPlayerOverlays ()J
|
|
||||||
public static final fun getScrimOverlay ()J
|
|
||||||
public static final fun getYtOutlinePictureInPictureWhite24 ()J
|
|
||||||
public static final fun getYtOutlineXWhite24 ()J
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatchKt {
|
public final class app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatchKt {
|
||||||
@@ -1382,6 +1406,12 @@ public final class app/revanced/patches/youtube/misc/playservice/VersionCheckPat
|
|||||||
public static final fun is_19_46_or_greater ()Z
|
public static final fun is_19_46_or_greater ()Z
|
||||||
public static final fun is_19_47_or_greater ()Z
|
public static final fun is_19_47_or_greater ()Z
|
||||||
public static final fun is_19_49_or_greater ()Z
|
public static final fun is_19_49_or_greater ()Z
|
||||||
|
public static final fun is_20_02_or_greater ()Z
|
||||||
|
public static final fun is_20_03_or_greater ()Z
|
||||||
|
public static final fun is_20_05_or_greater ()Z
|
||||||
|
public static final fun is_20_07_or_greater ()Z
|
||||||
|
public static final fun is_20_09_or_greater ()Z
|
||||||
|
public static final fun is_20_10_or_greater ()Z
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt {
|
public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt {
|
||||||
@@ -1495,7 +1525,11 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/util/BytecodeUtilsKt {
|
public final class app/revanced/util/BytecodeUtilsKt {
|
||||||
|
public static final fun addInstructionsAtControlFlowLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
||||||
|
public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;D)Z
|
||||||
|
public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;F)Z
|
||||||
public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
|
public static final fun containsLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
|
||||||
|
public static final fun findFreeRegister (Lcom/android/tools/smali/dexlib2/iface/Method;I[I)I
|
||||||
public static final fun findInstructionIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
|
public static final fun findInstructionIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
|
||||||
public static final fun findInstructionIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
|
public static final fun findInstructionIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
|
||||||
public static final fun findInstructionIndicesReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
|
public static final fun findInstructionIndicesReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
|
||||||
@@ -1522,9 +1556,17 @@ public final class app/revanced/util/BytecodeUtilsKt {
|
|||||||
public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I
|
public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I
|
||||||
public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I
|
public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I
|
||||||
public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
|
public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
|
||||||
|
public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;D)I
|
||||||
|
public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;F)I
|
||||||
public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
public static final fun indexOfFirstLiteralInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||||
|
public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;D)I
|
||||||
|
public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;F)I
|
||||||
public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
public static final fun indexOfFirstLiteralInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||||
|
public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;D)I
|
||||||
|
public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;F)I
|
||||||
public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
public static final fun indexOfFirstLiteralInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||||
|
public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;D)I
|
||||||
|
public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;F)I
|
||||||
public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
public static final fun indexOfFirstLiteralInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||||
public static final fun indexOfFirstResourceId (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
public static final fun indexOfFirstResourceId (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||||
public static final fun indexOfFirstResourceIdOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
public static final fun indexOfFirstResourceIdOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package app.revanced.patches.all.misc.targetSdk
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.util.getNode
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val setTargetSdkVersion34 = resourcePatch(
|
||||||
|
name = "Set target SDK version 34",
|
||||||
|
description = "Changes the target SDK to version 34 (Android 14). " +
|
||||||
|
"For devices running Android 15+, this will disable edge-to-edge display.",
|
||||||
|
use = false,
|
||||||
|
) {
|
||||||
|
execute {
|
||||||
|
val targetSdkOverride = 34 // Android 14.
|
||||||
|
|
||||||
|
document("AndroidManifest.xml").use { document ->
|
||||||
|
fun getLogger() = Logger.getLogger(this::class.java.name)
|
||||||
|
|
||||||
|
// Ideally, the override should only be applied if the existing target is higher.
|
||||||
|
// But since ApkTool does not add targetSdkVersion to the decompiled AndroidManifest,
|
||||||
|
// there is no way to check targetSdkVersion. Instead, check compileSdkVersion and print a warning.
|
||||||
|
try {
|
||||||
|
val manifestElement = document.getNode("manifest") as Element
|
||||||
|
val compileSdkVersion = Integer.parseInt(
|
||||||
|
manifestElement.getAttribute("android:compileSdkVersion")
|
||||||
|
)
|
||||||
|
if (compileSdkVersion <= targetSdkOverride) {
|
||||||
|
getLogger().warning(
|
||||||
|
"This app does not appear to use a target SDK above $targetSdkOverride: " +
|
||||||
|
"(compileSdkVersion: $compileSdkVersion)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
getLogger().warning("Could not check compileSdkVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change targetSdkVersion to override value.
|
||||||
|
document.getElementsByTagName("manifest").item(0).let {
|
||||||
|
var element = it.ownerDocument.createElement("uses-sdk")
|
||||||
|
element.setAttribute("android:targetSdkVersion", targetSdkOverride.toString())
|
||||||
|
|
||||||
|
it.appendChild(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package app.revanced.patches.angulus.ads
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
// Keywords to search for in case the method name changes:
|
||||||
|
// dailyMeasurementCount
|
||||||
|
// lastMeasurementDate
|
||||||
|
// dailyAdResetCount
|
||||||
|
// MeasurementPrefs
|
||||||
|
|
||||||
|
// This fingerprint targets a method that returns the daily measurement count.
|
||||||
|
// This method is used to determine if the user has reached the daily limit of measurements.
|
||||||
|
internal val getDailyMeasurementCountFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PRIVATE)
|
||||||
|
returns("I")
|
||||||
|
strings("dailyMeasurementCount")
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.patches.angulus.ads
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val angulusPatch = bytecodePatch(name = "Hide ads") {
|
||||||
|
compatibleWith("com.drinkplusplus.angulus")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
// Always return 0 as the daily measurement count.
|
||||||
|
getDailyMeasurementCountFingerprint.method.returnEarly()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
|||||||
val hideSponsoredStoriesPatch = bytecodePatch(
|
val hideSponsoredStoriesPatch = bytecodePatch(
|
||||||
name = "Hide 'Sponsored Stories'",
|
name = "Hide 'Sponsored Stories'",
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.facebook.katana")
|
compatibleWith("com.facebook.katana"("490.0.0.63.82"))
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod
|
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ private fun gmsCoreSupportResourcePatch(
|
|||||||
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
||||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
|
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
|
||||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||||
|
addStringResources = false,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ private fun gmsCoreSupportResourcePatch(
|
|||||||
) = app.revanced.patches.shared.misc.gms.gmsCoreSupportResourcePatch(
|
) = app.revanced.patches.shared.misc.gms.gmsCoreSupportResourcePatch(
|
||||||
fromPackageName = PHOTOS_PACKAGE_NAME,
|
fromPackageName = PHOTOS_PACKAGE_NAME,
|
||||||
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
|
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
|
||||||
|
addStringResources = false,
|
||||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
||||||
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,23 +3,28 @@ package app.revanced.patches.googlephotos.misc.preferences
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
@Deprecated("This patch no longer works and this code will soon be deleted")
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val restoreHiddenBackUpWhileChargingTogglePatch = bytecodePatch(
|
val restoreHiddenBackUpWhileChargingTogglePatch = bytecodePatch(
|
||||||
name = "Restore hidden 'Back up while charging' toggle",
|
description = "Restores a hidden toggle to only run backups when the device is charging."
|
||||||
description = "Restores a hidden toggle to only run backups when the device is charging.",
|
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.google.android.apps.photos")
|
compatibleWith("com.google.android.apps.photos"("7.11.0.705590205"))
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
// Patches 'backup_prefs_had_backup_only_when_charging_enabled' to always be true.
|
// Patches 'backup_prefs_had_backup_only_when_charging_enabled' to always be true.
|
||||||
val chargingPrefStringIndex = backupPreferencesFingerprint.stringMatches!!.first().index
|
backupPreferencesFingerprint.let {
|
||||||
backupPreferencesFingerprint.method.apply {
|
it.method.apply {
|
||||||
// Get the register of move-result.
|
val index = indexOfFirstInstructionOrThrow(
|
||||||
val resultRegister = getInstruction<OneRegisterInstruction>(chargingPrefStringIndex + 2).registerA
|
it.stringMatches!!.first().index,
|
||||||
// Insert const after move-result to override register as true.
|
Opcode.MOVE_RESULT
|
||||||
addInstruction(chargingPrefStringIndex + 3, "const/4 v$resultRegister, 0x1")
|
)
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
addInstruction(index + 1, "const/4 v$register, 0x1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package app.revanced.patches.messenger.navbar
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal val createTabConfigurationFingerprint = fingerprint {
|
||||||
|
strings("MessengerTabConfigurationCreator.createTabConfiguration")
|
||||||
|
opcodes(
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package app.revanced.patches.messenger.navbar
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val removeMetaAITabPatch = bytecodePatch(
|
||||||
|
name = "Remove Meta AI tab",
|
||||||
|
description = "Removes the 'Meta AI' tab from the navbar.",
|
||||||
|
) {
|
||||||
|
compatibleWith("com.facebook.orca")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
createTabConfigurationFingerprint.let {
|
||||||
|
val moveResultIndex = it.patternMatch!!.startIndex + 1
|
||||||
|
val enabledRegister = it.method.getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
|
||||||
|
it.method.replaceInstruction(
|
||||||
|
moveResultIndex,
|
||||||
|
"const/4 v$enabledRegister, 0x0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ val getDeviceIdPatch = bytecodePatch(
|
|||||||
) {
|
) {
|
||||||
dependsOn(signatureDetectionPatch)
|
dependsOn(signatureDetectionPatch)
|
||||||
|
|
||||||
compatibleWith("com.microblink.photomath"("8.37.0"))
|
compatibleWith("com.microblink.photomath")
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
getDeviceIdFingerprint.method.replaceInstructions(
|
getDeviceIdFingerprint.method.replaceInstructions(
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ internal val checkSignatureFingerprint = fingerprint {
|
|||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
Opcode.MOVE_RESULT,
|
Opcode.MOVE_RESULT,
|
||||||
)
|
)
|
||||||
strings("signatures")
|
strings("SHA")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ val hideUpdatePopupPatch = bytecodePatch(
|
|||||||
) {
|
) {
|
||||||
dependsOn(signatureDetectionPatch)
|
dependsOn(signatureDetectionPatch)
|
||||||
|
|
||||||
compatibleWith("com.microblink.photomath"("8.32.0"))
|
compatibleWith("com.microblink.photomath")
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
hideUpdatePopupFingerprint.method.addInstructions(
|
hideUpdatePopupFingerprint.method.addInstructions(
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ val unlockPlusPatch = bytecodePatch(
|
|||||||
) {
|
) {
|
||||||
dependsOn(signatureDetectionPatch, enableBookpointPatch)
|
dependsOn(signatureDetectionPatch, enableBookpointPatch)
|
||||||
|
|
||||||
compatibleWith("com.microblink.photomath"("8.37.0"))
|
compatibleWith("com.microblink.photomath")
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
isPlusUnlockedFingerprint.method.addInstructions(
|
isPlusUnlockedFingerprint.method.addInstructions(
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package app.revanced.patches.protonmail.signature
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.PatchException
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.util.findElementByAttributeValue
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val removeSentFromSignaturePatch = resourcePatch(
|
||||||
|
name = "Remove 'Sent from' signature",
|
||||||
|
description = "Removes the 'Sent from Proton Mail mobile' signature from emails.",
|
||||||
|
) {
|
||||||
|
compatibleWith("ch.protonmail.android")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
val stringResourceFiles = mutableListOf<File>()
|
||||||
|
|
||||||
|
get("res").walk().forEach { file ->
|
||||||
|
if (file.isFile && file.name.equals("strings.xml", ignoreCase = true)) {
|
||||||
|
stringResourceFiles.add(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var foundString = false
|
||||||
|
stringResourceFiles.forEach { filePath ->
|
||||||
|
document(filePath.absolutePath).use { document ->
|
||||||
|
var node = document.documentElement.childNodes.findElementByAttributeValue(
|
||||||
|
"name",
|
||||||
|
"mail_settings_identity_mobile_footer_default_free"
|
||||||
|
)
|
||||||
|
|
||||||
|
// String is not localized in all languages.
|
||||||
|
if (node != null) {
|
||||||
|
node.textContent = ""
|
||||||
|
foundString = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundString) throw PatchException("Could not find 'sent from' string in resources")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,11 +41,12 @@ fun sharedExtensionPatch(
|
|||||||
|
|
||||||
execute {
|
execute {
|
||||||
if (classes.none { EXTENSION_CLASS_DESCRIPTOR == it.type }) {
|
if (classes.none { EXTENSION_CLASS_DESCRIPTOR == it.type }) {
|
||||||
throw PatchException(
|
throw PatchException("Shared extension is not available. This patch can not succeed without it.")
|
||||||
"Shared extension has not been merged yet. This patch can not succeed without merging it.",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize {
|
||||||
|
// The hooks are made in finalize to ensure that the context is hooked before any other patches.
|
||||||
hooks.forEach { hook -> hook(EXTENSION_CLASS_DESCRIPTOR) }
|
hooks.forEach { hook -> hook(EXTENSION_CLASS_DESCRIPTOR) }
|
||||||
|
|
||||||
// Modify Utils method to include the patches release version.
|
// Modify Utils method to include the patches release version.
|
||||||
@@ -92,7 +93,7 @@ fun sharedExtensionPatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ExtensionHook internal constructor(
|
class ExtensionHook internal constructor(
|
||||||
private val fingerprint: Fingerprint,
|
internal val fingerprint: Fingerprint,
|
||||||
private val insertIndexResolver: ((Method) -> Int),
|
private val insertIndexResolver: ((Method) -> Int),
|
||||||
private val contextRegisterResolver: (Method) -> String,
|
private val contextRegisterResolver: (Method) -> String,
|
||||||
) {
|
) {
|
||||||
@@ -109,8 +110,14 @@ class ExtensionHook internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun extensionHook(
|
||||||
|
insertIndexResolver: ((Method) -> Int) = { 0 },
|
||||||
|
contextRegisterResolver: (Method) -> String = { "p0" },
|
||||||
|
fingerprint: Fingerprint,
|
||||||
|
) = ExtensionHook(fingerprint, insertIndexResolver, contextRegisterResolver)
|
||||||
|
|
||||||
fun extensionHook(
|
fun extensionHook(
|
||||||
insertIndexResolver: ((Method) -> Int) = { 0 },
|
insertIndexResolver: ((Method) -> Int) = { 0 },
|
||||||
contextRegisterResolver: (Method) -> String = { "p0" },
|
contextRegisterResolver: (Method) -> String = { "p0" },
|
||||||
fingerprintBuilderBlock: FingerprintBuilder.() -> Unit,
|
fingerprintBuilderBlock: FingerprintBuilder.() -> Unit,
|
||||||
) = ExtensionHook(fingerprint(block = fingerprintBuilderBlock), insertIndexResolver, contextRegisterResolver)
|
) = extensionHook(insertIndexResolver, contextRegisterResolver, fingerprint(block = fingerprintBuilderBlock))
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import com.android.tools.smali.dexlib2.Opcode
|
|||||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
|
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
|
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||||
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
|
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
@@ -110,19 +109,18 @@ fun gmsCoreSupportPatch(
|
|||||||
|
|
||||||
// region Collection of transformations that are applied to all strings.
|
// region Collection of transformations that are applied to all strings.
|
||||||
|
|
||||||
fun commonTransform(referencedString: String): String? =
|
fun commonTransform(referencedString: String): String? = when (referencedString) {
|
||||||
when (referencedString) {
|
"com.google",
|
||||||
"com.google",
|
"com.google.android.gms",
|
||||||
"com.google.android.gms",
|
in PERMISSIONS,
|
||||||
in PERMISSIONS,
|
in ACTIONS,
|
||||||
in ACTIONS,
|
in AUTHORITIES,
|
||||||
in AUTHORITIES,
|
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
|
||||||
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
|
|
||||||
|
|
||||||
// No vendor prefix for whatever reason...
|
// No vendor prefix for whatever reason...
|
||||||
"subscribedfeeds" -> "$gmsCoreVendorGroupId.subscribedfeeds"
|
"subscribedfeeds" -> "$gmsCoreVendorGroupId.subscribedfeeds"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun contentUrisTransform(str: String): String? {
|
fun contentUrisTransform(str: String): String? {
|
||||||
// only when content:// uri
|
// only when content:// uri
|
||||||
@@ -205,16 +203,8 @@ fun gmsCoreSupportPatch(
|
|||||||
|
|
||||||
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
|
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
|
||||||
mainActivityOnCreateFingerprint.method.apply {
|
mainActivityOnCreateFingerprint.method.apply {
|
||||||
// Temporary fix for patches with an extension patch that hook the onCreate method as well.
|
|
||||||
val setContextIndex = indexOfFirstInstruction {
|
|
||||||
val reference = getReference<MethodReference>() ?: return@indexOfFirstInstruction false
|
|
||||||
|
|
||||||
reference.toString() == "Lapp/revanced/extension/shared/Utils;->setContext(Landroid/content/Context;)V"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add after setContext call, because this patch needs the context.
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
if (setContextIndex < 0) 0 else setContextIndex + 1,
|
0,
|
||||||
"invoke-static/range { p0 .. p0 }, Lapp/revanced/extension/shared/GmsCoreSupport;->" +
|
"invoke-static/range { p0 .. p0 }, Lapp/revanced/extension/shared/GmsCoreSupport;->" +
|
||||||
"checkGmsCore(Landroid/app/Activity;)V",
|
"checkGmsCore(Landroid/app/Activity;)V",
|
||||||
)
|
)
|
||||||
@@ -510,13 +500,44 @@ private object Constants {
|
|||||||
* @param executeBlock The additional execution block of the patch.
|
* @param executeBlock The additional execution block of the patch.
|
||||||
* @param block The additional block to build the patch.
|
* @param block The additional block to build the patch.
|
||||||
*/
|
*/
|
||||||
fun gmsCoreSupportResourcePatch(
|
fun gmsCoreSupportResourcePatch( // This is here only for binary compatibility.
|
||||||
fromPackageName: String,
|
fromPackageName: String,
|
||||||
toPackageName: String,
|
toPackageName: String,
|
||||||
spoofedPackageSignature: String,
|
spoofedPackageSignature: String,
|
||||||
gmsCoreVendorGroupIdOption: Option<String>,
|
gmsCoreVendorGroupIdOption: Option<String>,
|
||||||
executeBlock: ResourcePatchContext.() -> Unit = {},
|
executeBlock: ResourcePatchContext.() -> Unit = {},
|
||||||
block: ResourcePatchBuilder.() -> Unit = {},
|
block: ResourcePatchBuilder.() -> Unit = {},
|
||||||
|
) = gmsCoreSupportResourcePatch(
|
||||||
|
fromPackageName,
|
||||||
|
toPackageName,
|
||||||
|
spoofedPackageSignature,
|
||||||
|
gmsCoreVendorGroupIdOption,
|
||||||
|
true,
|
||||||
|
executeBlock,
|
||||||
|
block
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract resource patch that allows Google apps to run without root and under a different package name
|
||||||
|
* by using GmsCore instead of Google Play Services.
|
||||||
|
*
|
||||||
|
* @param fromPackageName The package name of the original app.
|
||||||
|
* @param toPackageName The package name to fall back to if no custom package name is specified in patch options.
|
||||||
|
* @param spoofedPackageSignature The signature of the package to spoof to.
|
||||||
|
* @param gmsCoreVendorGroupIdOption The option to get the vendor group ID of GmsCore.
|
||||||
|
* @param addStringResources If the GmsCore shared strings should be added to the patched app.
|
||||||
|
* @param executeBlock The additional execution block of the patch.
|
||||||
|
* @param block The additional block to build the patch.
|
||||||
|
*/
|
||||||
|
// TODO: On the next major release make this public and delete the public overloaded constructor.
|
||||||
|
internal fun gmsCoreSupportResourcePatch(
|
||||||
|
fromPackageName: String,
|
||||||
|
toPackageName: String,
|
||||||
|
spoofedPackageSignature: String,
|
||||||
|
gmsCoreVendorGroupIdOption: Option<String>,
|
||||||
|
addStringResources: Boolean = true,
|
||||||
|
executeBlock: ResourcePatchContext.() -> Unit = {},
|
||||||
|
block: ResourcePatchBuilder.() -> Unit = {},
|
||||||
) = resourcePatch {
|
) = resourcePatch {
|
||||||
dependsOn(
|
dependsOn(
|
||||||
changePackageNamePatch,
|
changePackageNamePatch,
|
||||||
@@ -526,7 +547,10 @@ fun gmsCoreSupportResourcePatch(
|
|||||||
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
|
// Some patches don't use shared String resources so there's no need to add them.
|
||||||
|
if (addStringResources) {
|
||||||
|
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add metadata to manifest to support spoofing the package name and signature of GmsCore.
|
* Add metadata to manifest to support spoofing the package name and signature of GmsCore.
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import app.revanced.patches.all.misc.resources.addResources
|
|||||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.BasePreference
|
import app.revanced.patches.shared.misc.settings.preference.BasePreference
|
||||||
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
|
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||||
import app.revanced.util.ResourceGroup
|
import app.revanced.util.ResourceGroup
|
||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
import app.revanced.util.getNode
|
import app.revanced.util.getNode
|
||||||
@@ -36,14 +38,14 @@ fun settingsPatch (
|
|||||||
execute {
|
execute {
|
||||||
copyResources(
|
copyResources(
|
||||||
"settings",
|
"settings",
|
||||||
ResourceGroup("xml", "revanced_prefs.xml"),
|
ResourceGroup("xml", "revanced_prefs.xml", "revanced_prefs_icons.xml"),
|
||||||
)
|
)
|
||||||
|
|
||||||
addResources("shared", "misc.settings.settingsResourcePatch")
|
addResources("shared", "misc.settings.settingsResourcePatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
finalize {
|
finalize {
|
||||||
fun Node.addPreference(preference: BasePreference, prepend: Boolean = false) {
|
fun Node.addPreference(preference: BasePreference) {
|
||||||
preference.serialize(ownerDocument) { resource ->
|
preference.serialize(ownerDocument) { resource ->
|
||||||
// TODO: Currently, resources can only be added to "values", which may not be the correct place.
|
// TODO: Currently, resources can only be added to "values", which may not be the correct place.
|
||||||
// It may be necessary to ask for the desired resourceValue in the future.
|
// It may be necessary to ask for the desired resourceValue in the future.
|
||||||
@@ -61,7 +63,7 @@ fun settingsPatch (
|
|||||||
val preferenceFileName = "res/xml/$fileName.xml"
|
val preferenceFileName = "res/xml/$fileName.xml"
|
||||||
if (get(preferenceFileName).exists()) {
|
if (get(preferenceFileName).exists()) {
|
||||||
document(preferenceFileName).use { document ->
|
document(preferenceFileName).use { document ->
|
||||||
document.getNode("PreferenceScreen").addPreference(intent, true)
|
document.getNode("PreferenceScreen").addPreference(intent)
|
||||||
}
|
}
|
||||||
modified = true
|
modified = true
|
||||||
}
|
}
|
||||||
@@ -71,6 +73,30 @@ fun settingsPatch (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add all preferences to the ReVanced fragment.
|
// Add all preferences to the ReVanced fragment.
|
||||||
|
document("res/xml/revanced_prefs_icons.xml").use { document ->
|
||||||
|
val revancedPreferenceScreenNode = document.getNode("PreferenceScreen")
|
||||||
|
preferences.forEach { revancedPreferenceScreenNode.addPreference(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because the icon preferences require declaring a layout resource,
|
||||||
|
// there is no easy way to change to the Android default preference layout
|
||||||
|
// after the preference is inflated.
|
||||||
|
// Using two different preference files is the simplest and most robust solution.
|
||||||
|
fun removeIconsAndLayout(preferences: Collection<BasePreference>) {
|
||||||
|
preferences.forEach { preference ->
|
||||||
|
preference.icon = null
|
||||||
|
preference.layout = null
|
||||||
|
|
||||||
|
if (preference is PreferenceCategory) {
|
||||||
|
removeIconsAndLayout(preference.preferences)
|
||||||
|
}
|
||||||
|
if (preference is PreferenceScreenPreference) {
|
||||||
|
removeIconsAndLayout(preference.preferences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeIconsAndLayout(preferences)
|
||||||
|
|
||||||
document("res/xml/revanced_prefs.xml").use { document ->
|
document("res/xml/revanced_prefs.xml").use { document ->
|
||||||
val revancedPreferenceScreenNode = document.getNode("PreferenceScreen")
|
val revancedPreferenceScreenNode = document.getNode("PreferenceScreen")
|
||||||
preferences.forEach { revancedPreferenceScreenNode.addPreference(it) }
|
preferences.forEach { revancedPreferenceScreenNode.addPreference(it) }
|
||||||
|
|||||||
@@ -19,10 +19,17 @@ abstract class BasePreference(
|
|||||||
val key: String? = null,
|
val key: String? = null,
|
||||||
val titleKey: String? = "${key}_title",
|
val titleKey: String? = "${key}_title",
|
||||||
val summaryKey: String? = "${key}_summary",
|
val summaryKey: String? = "${key}_summary",
|
||||||
val icon: String? = null,
|
icon: String? = null,
|
||||||
val layout: String? = null,
|
layout: String? = null,
|
||||||
val tag: String
|
val tag: String
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
var icon: String? = icon
|
||||||
|
internal set
|
||||||
|
|
||||||
|
var layout: String? = layout
|
||||||
|
internal set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize preference element to XML.
|
* Serialize preference element to XML.
|
||||||
* Overriding methods should invoke super and operate on its return value.
|
* Overriding methods should invoke super and operate on its return value.
|
||||||
|
|||||||
@@ -145,7 +145,25 @@ internal val patchIncludedExtensionMethodFingerprint = fingerprint {
|
|||||||
internal const val MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG = 45645570L
|
internal const val MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG = 45645570L
|
||||||
|
|
||||||
internal val mediaFetchHotConfigFingerprint = fingerprint {
|
internal val mediaFetchHotConfigFingerprint = fingerprint {
|
||||||
literal {
|
literal { MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG }
|
||||||
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG
|
}
|
||||||
}
|
|
||||||
|
// 20.10+
|
||||||
|
internal const val MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG = 45683169L
|
||||||
|
|
||||||
|
internal val mediaFetchHotConfigAlternativeFingerprint = fingerprint {
|
||||||
|
literal { MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feature flag that enables different code for parsing and starting video playback,
|
||||||
|
// but it's exact purpose is not known. If this flag is enabled while stream spoofing
|
||||||
|
// then videos will never start playback and load forever.
|
||||||
|
// Flag does not seem to affect playback if spoofing is off.
|
||||||
|
internal const val PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG = 45665455L
|
||||||
|
|
||||||
|
internal val playbackStartDescriptorFeatureFlagFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
|
parameters()
|
||||||
|
returns("Z")
|
||||||
|
literal { PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import app.revanced.patcher.patch.BytecodePatchContext
|
|||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.util.findFreeRegister
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
import app.revanced.util.insertFeatureFlagBooleanOverride
|
import app.revanced.util.insertLiteralOverride
|
||||||
import app.revanced.util.returnEarly
|
import app.revanced.util.returnEarly
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
@@ -31,7 +32,9 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
|
|||||||
|
|
||||||
fun spoofVideoStreamsPatch(
|
fun spoofVideoStreamsPatch(
|
||||||
block: BytecodePatchBuilder.() -> Unit = {},
|
block: BytecodePatchBuilder.() -> Unit = {},
|
||||||
applyMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
|
fixMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
|
||||||
|
fixMediaFetchHotConfigAlternativeChanges: BytecodePatchBuilder.() -> Boolean = { false },
|
||||||
|
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
|
||||||
executeBlock: BytecodePatchContext.() -> Unit = {},
|
executeBlock: BytecodePatchContext.() -> Unit = {},
|
||||||
) = bytecodePatch(
|
) = bytecodePatch(
|
||||||
name = "Spoof video streams",
|
name = "Spoof video streams",
|
||||||
@@ -92,14 +95,14 @@ fun spoofVideoStreamsPatch(
|
|||||||
getReference<MethodReference>()?.name == "newUrlRequestBuilder"
|
getReference<MethodReference>()?.name == "newUrlRequestBuilder"
|
||||||
}
|
}
|
||||||
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
|
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
|
||||||
val freeRegister = getInstruction<OneRegisterInstruction>(newRequestBuilderIndex + 1).registerA
|
val freeRegister = findFreeRegister(newRequestBuilderIndex, urlRegister)
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
newRequestBuilderIndex,
|
newRequestBuilderIndex,
|
||||||
"""
|
"""
|
||||||
move-object v$freeRegister, p1
|
move-object v$freeRegister, p1
|
||||||
invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V
|
invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V
|
||||||
""",
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +235,7 @@ fun spoofVideoStreamsPatch(
|
|||||||
|
|
||||||
// region Fix iOS livestream current time.
|
// region Fix iOS livestream current time.
|
||||||
|
|
||||||
hlsCurrentTimeFingerprint.method.insertFeatureFlagBooleanOverride(
|
hlsCurrentTimeFingerprint.method.insertLiteralOverride(
|
||||||
HLS_CURRENT_TIME_FEATURE_FLAG,
|
HLS_CURRENT_TIME_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z"
|
||||||
)
|
)
|
||||||
@@ -241,13 +244,27 @@ fun spoofVideoStreamsPatch(
|
|||||||
|
|
||||||
// region turn off stream config replacement feature flag.
|
// region turn off stream config replacement feature flag.
|
||||||
|
|
||||||
if (applyMediaFetchHotConfigChanges()) {
|
if (fixMediaFetchHotConfigChanges()) {
|
||||||
mediaFetchHotConfigFingerprint.method.insertFeatureFlagBooleanOverride(
|
mediaFetchHotConfigFingerprint.method.insertLiteralOverride(
|
||||||
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
|
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fixMediaFetchHotConfigAlternativeChanges()) {
|
||||||
|
mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride(
|
||||||
|
MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixParsePlaybackResponseFeatureFlag()) {
|
||||||
|
playbackStartDescriptorFeatureFlagFingerprint.method.insertLiteralOverride(
|
||||||
|
PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
executeBlock()
|
executeBlock()
|
||||||
|
|||||||
@@ -1,80 +1,205 @@
|
|||||||
@file:Suppress("NAME_SHADOWING")
|
|
||||||
|
|
||||||
package app.revanced.patches.spotify.layout.theme
|
package app.revanced.patches.spotify.layout.theme
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.patcher.patch.booleanOption
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
import app.revanced.patcher.patch.stringOption
|
import app.revanced.patcher.patch.stringOption
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||||
|
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.util.*
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/layout/theme/CustomThemePatch;"
|
||||||
|
|
||||||
|
internal val spotifyBackgroundColor = stringOption(
|
||||||
|
key = "backgroundColor",
|
||||||
|
default = "@android:color/black",
|
||||||
|
title = "Primary background color",
|
||||||
|
description = "The background color. Can be a hex color or a resource reference.",
|
||||||
|
required = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val overridePlayerGradientColor = booleanOption(
|
||||||
|
key = "overridePlayerGradientColor",
|
||||||
|
default = false,
|
||||||
|
title = "Override player gradient color",
|
||||||
|
description = "Apply primary background color to the player gradient color, which changes dynamically with the song.",
|
||||||
|
required = false
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val spotifyBackgroundColorSecondary = stringOption(
|
||||||
|
key = "backgroundColorSecondary",
|
||||||
|
default = "#FF121212",
|
||||||
|
title = "Secondary background color",
|
||||||
|
description =
|
||||||
|
"The secondary background color. (e.g. playlist list in home, player artist, song credits). Can be a hex color or a resource reference.",
|
||||||
|
required = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val spotifyAccentColor = stringOption(
|
||||||
|
key = "accentColor",
|
||||||
|
default = "#FF1ED760",
|
||||||
|
title = "Accent color",
|
||||||
|
description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.",
|
||||||
|
required = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val spotifyAccentColorPressed = stringOption(
|
||||||
|
key = "accentColorPressed",
|
||||||
|
default = "#FF169C46",
|
||||||
|
title = "Pressed dark theme accent color",
|
||||||
|
description =
|
||||||
|
"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.",
|
||||||
|
required = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val customThemeBytecodePatch = bytecodePatch {
|
||||||
|
dependsOn(sharedExtensionPatch)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||||
|
// Bytecode changes are not needed for legacy app target.
|
||||||
|
// Player background color is changed with existing resource patch.
|
||||||
|
return@execute
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MutableMethod.addColorChangeInstructions(literal: Long, colorString: String) {
|
||||||
|
val index = indexOfFirstLiteralInstructionOrThrow(literal)
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
index + 1,
|
||||||
|
"""
|
||||||
|
const-string v$register, "$colorString"
|
||||||
|
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getThemeColor(Ljava/lang/String;)J
|
||||||
|
move-result-wide v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val encoreColorsClassName = with(encoreThemeFingerprint.originalMethod) {
|
||||||
|
// "Encore" colors are referenced right before the value of POSITIVE_INFINITY is returned.
|
||||||
|
// Begin the instruction find using the index of where POSITIVE_INFINITY is set into the register.
|
||||||
|
val positiveInfinityIndex = indexOfFirstLiteralInstructionOrThrow(
|
||||||
|
Float.POSITIVE_INFINITY
|
||||||
|
)
|
||||||
|
val encoreColorsFieldReferenceIndex = indexOfFirstInstructionReversedOrThrow(
|
||||||
|
positiveInfinityIndex,
|
||||||
|
Opcode.SGET_OBJECT
|
||||||
|
)
|
||||||
|
|
||||||
|
getInstruction(encoreColorsFieldReferenceIndex)
|
||||||
|
.getReference<FieldReference>()!!.definingClass
|
||||||
|
}
|
||||||
|
|
||||||
|
val encoreColorsConstructorFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||||
|
custom { method, classDef ->
|
||||||
|
classDef.type == encoreColorsClassName &&
|
||||||
|
method.containsLiteralInstruction(PLAYLIST_BACKGROUND_COLOR_LITERAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val backgroundColor by spotifyBackgroundColor
|
||||||
|
val backgroundColorSecondary by spotifyBackgroundColorSecondary
|
||||||
|
|
||||||
|
encoreColorsConstructorFingerprint.method.apply {
|
||||||
|
addColorChangeInstructions(PLAYLIST_BACKGROUND_COLOR_LITERAL, backgroundColor!!)
|
||||||
|
addColorChangeInstructions(SHARE_MENU_BACKGROUND_COLOR_LITERAL, backgroundColorSecondary!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
homeCategoryPillColorsFingerprint.method.addColorChangeInstructions(
|
||||||
|
HOME_CATEGORY_PILL_COLOR_LITERAL,
|
||||||
|
backgroundColorSecondary!!
|
||||||
|
)
|
||||||
|
|
||||||
|
settingsHeaderColorFingerprint.method.addColorChangeInstructions(
|
||||||
|
SETTINGS_HEADER_COLOR_LITERAL,
|
||||||
|
backgroundColorSecondary!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val customThemePatch = resourcePatch(
|
val customThemePatch = resourcePatch(
|
||||||
name = "Custom theme",
|
name = "Custom theme",
|
||||||
description = "Applies a custom theme.",
|
description = "Applies a custom theme (defaults to amoled black)",
|
||||||
|
use = false,
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.spotify.music")
|
compatibleWith("com.spotify.music")
|
||||||
|
|
||||||
val backgroundColor by stringOption(
|
dependsOn(customThemeBytecodePatch)
|
||||||
key = "backgroundColor",
|
|
||||||
default = "@android:color/black",
|
|
||||||
title = "Primary background color",
|
|
||||||
description = "The background color. Can be a hex color or a resource reference.",
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
val backgroundColorSecondary by stringOption(
|
val backgroundColor by spotifyBackgroundColor()
|
||||||
key = "backgroundColorSecondary",
|
val overridePlayerGradientColor by overridePlayerGradientColor()
|
||||||
default = "#ff282828",
|
val backgroundColorSecondary by spotifyBackgroundColorSecondary()
|
||||||
title = "Secondary background color",
|
val accentColor by spotifyAccentColor()
|
||||||
description = "The secondary background color. (e.g. search box, artist & podcast). Can be a hex color or a resource reference.",
|
val accentColorPressed by spotifyAccentColorPressed()
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
val accentColor by stringOption(
|
|
||||||
key = "accentColor",
|
|
||||||
default = "#ff1ed760",
|
|
||||||
title = "Accent color",
|
|
||||||
description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.",
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
val accentColorPressed by stringOption(
|
|
||||||
key = "accentColorPressed",
|
|
||||||
default = "#ff169c46",
|
|
||||||
title = "Pressed dark theme accent color",
|
|
||||||
description =
|
|
||||||
"The color when accented buttons are pressed, by default slightly darker than accent. " +
|
|
||||||
"Can be a hex color or a resource reference.",
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
val backgroundColor = backgroundColor!!
|
|
||||||
val backgroundColorSecondary = backgroundColorSecondary!!
|
|
||||||
val accentColor = accentColor!!
|
|
||||||
val accentColorPressed = accentColorPressed!!
|
|
||||||
|
|
||||||
document("res/values/colors.xml").use { document ->
|
document("res/values/colors.xml").use { document ->
|
||||||
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
||||||
|
|
||||||
val childNodes = resourcesNode.childNodes
|
val childNodes = resourcesNode.childNodes
|
||||||
for (i in 0 until childNodes.length) {
|
for (i in 0 until childNodes.length) {
|
||||||
val node = childNodes.item(i) as? Element ?: continue
|
val node = childNodes.item(i) as? Element ?: continue
|
||||||
|
val name = node.getAttribute("name")
|
||||||
|
|
||||||
node.textContent =
|
// Skip overriding song/player gradient start color if the option is disabled.
|
||||||
when (node.getAttribute("name")) {
|
// Gradient end color should be themed regardless to allow the gradient to connect with
|
||||||
"dark_base_background_elevated_base", "design_dark_default_color_background",
|
// our primary background color.
|
||||||
"design_dark_default_color_surface", "gray_7", "gray_background", "gray_layer",
|
if (name == "bg_gradient_start_color" && !overridePlayerGradientColor!!) {
|
||||||
"sthlm_blk",
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
node.textContent = when (name) {
|
||||||
|
// Gradient next to user photo and "All" in home page.
|
||||||
|
"dark_base_background_base",
|
||||||
|
// Main background.
|
||||||
|
"gray_7",
|
||||||
|
// Left sidebar background in tablet mode.
|
||||||
|
"gray_10",
|
||||||
|
// "Add account", "Settings and privacy", "View Profile" left sidebar background.
|
||||||
|
"dark_base_background_elevated_base",
|
||||||
|
// Song/player gradient start/end color.
|
||||||
|
"bg_gradient_start_color", "bg_gradient_end_color",
|
||||||
|
// Login screen background and gradient start.
|
||||||
|
"sthlm_blk", "sthlm_blk_grad_start",
|
||||||
|
// Misc.
|
||||||
|
"image_placeholder_color",
|
||||||
-> backgroundColor
|
-> backgroundColor
|
||||||
|
|
||||||
"gray_15" -> backgroundColorSecondary
|
// Track credits, merch background in song player.
|
||||||
|
"track_credits_card_bg", "benefit_list_default_color", "merch_card_background",
|
||||||
|
// Playlist list background in home page.
|
||||||
|
"opacity_white_10",
|
||||||
|
// "About the artist" background in song player.
|
||||||
|
"gray_15",
|
||||||
|
// "What's New" pills background.
|
||||||
|
"dark_base_background_tinted_highlight"
|
||||||
|
-> backgroundColorSecondary
|
||||||
|
|
||||||
"dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor
|
"dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor
|
||||||
|
"dark_brightaccent_background_press" -> accentColorPressed
|
||||||
"dark_brightaccent_background_press" -> accentColorPressed
|
else -> continue
|
||||||
else -> continue
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Login screen gradient.
|
||||||
|
document("res/drawable/start_screen_gradient.xml").use { document ->
|
||||||
|
val gradientNode = document.getElementsByTagName("gradient").item(0) as Element
|
||||||
|
|
||||||
|
gradientNode.setAttribute("android:startColor", backgroundColor)
|
||||||
|
gradientNode.setAttribute("android:endColor", backgroundColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package app.revanced.patches.spotify.layout.theme
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.util.containsLiteralInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal val encoreThemeFingerprint = fingerprint {
|
||||||
|
strings("No EncoreLayoutTheme provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal const val PLAYLIST_BACKGROUND_COLOR_LITERAL = 0xFF121212
|
||||||
|
internal const val SHARE_MENU_BACKGROUND_COLOR_LITERAL = 0xFF1F1F1F
|
||||||
|
internal const val HOME_CATEGORY_PILL_COLOR_LITERAL = 0xFF333333
|
||||||
|
internal const val SETTINGS_HEADER_COLOR_LITERAL = 0xFF282828
|
||||||
|
|
||||||
|
internal val homeCategoryPillColorsFingerprint = fingerprint{
|
||||||
|
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||||
|
custom { method, _ ->
|
||||||
|
method.containsLiteralInstruction(HOME_CATEGORY_PILL_COLOR_LITERAL) &&
|
||||||
|
method.containsLiteralInstruction(0x33000000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val settingsHeaderColorFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||||
|
custom { method, _ ->
|
||||||
|
method.containsLiteralInstruction(SETTINGS_HEADER_COLOR_LITERAL) &&
|
||||||
|
method.containsLiteralInstruction(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package app.revanced.patches.spotify.misc
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.patches.spotify.misc.extension.IS_SPOTIFY_LEGACY_APP_TARGET
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
internal val accountAttributeFingerprint = fingerprint {
|
||||||
|
custom { _, classDef ->
|
||||||
|
classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||||
|
"Lcom/spotify/useraccount/v1/AccountAttribute;"
|
||||||
|
} else {
|
||||||
|
"Lcom/spotify/remoteconfig/internal/AccountAttribute;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val productStateProtoFingerprint = fingerprint {
|
||||||
|
returns("Ljava/util/Map;")
|
||||||
|
custom { _, classDef ->
|
||||||
|
classDef.type == if (IS_SPOTIFY_LEGACY_APP_TARGET) {
|
||||||
|
"Lcom/spotify/ucs/proto/v0/UcsResponseWrapper${'$'}AccountAttributesResponse;"
|
||||||
|
} else {
|
||||||
|
"Lcom/spotify/remoteconfig/internal/ProductStateProto;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val buildQueryParametersFingerprint = fingerprint {
|
||||||
|
strings("trackRows", "device_type:tablet")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val contextMenuExperimentsFingerprint = fingerprint {
|
||||||
|
parameters("L")
|
||||||
|
strings("remove_ads_upsell_enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val contextFromJsonFingerprint = fingerprint {
|
||||||
|
opcodes(
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_STATIC
|
||||||
|
)
|
||||||
|
custom { methodDef, classDef ->
|
||||||
|
methodDef.name == "fromJson" &&
|
||||||
|
classDef.endsWith("voiceassistants/playermodels/ContextJsonAdapter;")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val readPlayerOptionOverridesFingerprint = fingerprint {
|
||||||
|
custom { methodDef, classDef ->
|
||||||
|
methodDef.name == "readPlayerOptionOverrides" &&
|
||||||
|
classDef.endsWith("voiceassistants/playermodels/PreparePlayOptionsJsonAdapter;")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val homeSectionFingerprint = fingerprint {
|
||||||
|
custom { _, classDef -> classDef.endsWith("homeapi/proto/Section;") }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val protobufListsFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||||
|
custom { method, _ -> method.name == "emptyProtobufList" }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val homeStructureFingerprint = fingerprint {
|
||||||
|
opcodes(Opcode.IGET_OBJECT, Opcode.RETURN_OBJECT)
|
||||||
|
custom { _, classDef -> classDef.endsWith("homeapi/proto/HomeStructure;") }
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package app.revanced.patches.spotify.misc.check
|
||||||
|
|
||||||
|
import app.revanced.patches.shared.misc.checks.checkEnvironmentPatch
|
||||||
|
import app.revanced.patches.spotify.shared.mainActivityOnCreateFingerprint
|
||||||
|
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
|
||||||
|
|
||||||
|
internal val checkEnvironmentPatch = checkEnvironmentPatch(
|
||||||
|
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||||
|
extensionPatch = sharedExtensionPatch,
|
||||||
|
"com.spotify.music",
|
||||||
|
)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patches.spotify.misc.extension
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.spotify.shared.SPOTIFY_MAIN_ACTIVITY_LEGACY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If patching a legacy 8.x target. This may also be set if patching slightly older/newer app targets,
|
||||||
|
* but the only legacy target of interest is 8.6.98.900 as it's the last version that
|
||||||
|
* supports Spotify integration on Kenwood/Pioneer car stereos.
|
||||||
|
*/
|
||||||
|
internal var IS_SPOTIFY_LEGACY_APP_TARGET = false
|
||||||
|
|
||||||
|
val sharedExtensionPatch = bytecodePatch {
|
||||||
|
dependsOn(sharedExtensionPatch("spotify", mainActivityOnCreateHook))
|
||||||
|
|
||||||
|
execute {
|
||||||
|
IS_SPOTIFY_LEGACY_APP_TARGET = mainActivityOnCreateHook.fingerprint
|
||||||
|
.originalClassDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package app.revanced.patches.spotify.misc.extension
|
||||||
|
|
||||||
|
import app.revanced.patches.shared.misc.extension.extensionHook
|
||||||
|
import app.revanced.patches.spotify.shared.mainActivityOnCreateFingerprint
|
||||||
|
|
||||||
|
internal val mainActivityOnCreateHook = extensionHook(fingerprint = mainActivityOnCreateFingerprint)
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package app.revanced.patches.spotify.navbar
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint
|
|
||||||
import app.revanced.util.literal
|
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
internal val addNavBarItemFingerprint = fingerprint {
|
|
||||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
|
||||||
returns("V")
|
|
||||||
literal { showBottomNavigationItemsTextId }
|
|
||||||
}
|
|
||||||
@@ -1,50 +1,12 @@
|
|||||||
package app.revanced.patches.spotify.navbar
|
package app.revanced.patches.spotify.navbar
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patches.spotify.misc.unlockPremiumPatch
|
||||||
import app.revanced.patches.shared.misc.mapping.get
|
|
||||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
|
||||||
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
|
||||||
|
|
||||||
internal var showBottomNavigationItemsTextId = -1L
|
|
||||||
private set
|
|
||||||
internal var premiumTabId = -1L
|
|
||||||
private set
|
|
||||||
|
|
||||||
private val premiumNavbarTabResourcePatch = resourcePatch {
|
|
||||||
dependsOn(resourceMappingPatch)
|
|
||||||
|
|
||||||
execute {
|
|
||||||
premiumTabId = resourceMappings["id", "premium_tab"]
|
|
||||||
|
|
||||||
showBottomNavigationItemsTextId = resourceMappings[
|
|
||||||
"bool",
|
|
||||||
"show_bottom_navigation_items_text",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Deprecated("Superseded by unlockPremiumPatch", ReplaceWith("unlockPremiumPatch"))
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val premiumNavbarTabPatch = bytecodePatch(
|
val premiumNavbarTabPatch = bytecodePatch(
|
||||||
name = "Premium navbar tab",
|
|
||||||
description = "Hides the premium tab from the navigation bar.",
|
description = "Hides the premium tab from the navigation bar.",
|
||||||
) {
|
) {
|
||||||
dependsOn(premiumNavbarTabResourcePatch)
|
dependsOn(unlockPremiumPatch)
|
||||||
|
|
||||||
compatibleWith("com.spotify.music")
|
|
||||||
|
|
||||||
// If the navigation bar item is the premium tab, do not add it.
|
|
||||||
execute {
|
|
||||||
addNavBarItemFingerprint.method.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const v1, $premiumTabId
|
|
||||||
if-ne p5, v1, :continue
|
|
||||||
return-void
|
|
||||||
:continue
|
|
||||||
nop
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.patches.spotify.shared
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main activity of target 8.6.98.900.
|
||||||
|
*/
|
||||||
|
internal const val SPOTIFY_MAIN_ACTIVITY_LEGACY = "Lcom/spotify/music/MainActivity;"
|
||||||
|
|
||||||
|
internal val mainActivityOnCreateFingerprint = fingerprint {
|
||||||
|
custom { method, classDef ->
|
||||||
|
method.name == "onCreate" && (classDef.type == SPOTIFY_MAIN_ACTIVITY
|
||||||
|
|| classDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
|||||||
val disableSubscriptionSuggestionsPatch = bytecodePatch(
|
val disableSubscriptionSuggestionsPatch = bytecodePatch(
|
||||||
name = "Disable subscription suggestions",
|
name = "Disable subscription suggestions",
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.strava"("320.12"))
|
compatibleWith("com.strava")
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
val helperMethodName = "getModulesIfNotUpselling"
|
val helperMethodName = "getModulesIfNotUpselling"
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ val dynamicColorPatch = resourcePatch(
|
|||||||
name = "Dynamic color",
|
name = "Dynamic color",
|
||||||
description = "Replaces the default X (Formerly Twitter) Blue with the user's Material You palette.",
|
description = "Replaces the default X (Formerly Twitter) Blue with the user's Material You palette.",
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.twitter.android")
|
compatibleWith(
|
||||||
|
"com.twitter.android"(
|
||||||
|
"10.84.0-release.0",
|
||||||
|
"10.60.0-release.0",
|
||||||
|
"10.48.0-release.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
val resDirectory = get("res")
|
val resDirectory = get("res")
|
||||||
|
|||||||
@@ -11,7 +11,15 @@ fun hookPatch(
|
|||||||
) = bytecodePatch(name) {
|
) = bytecodePatch(name) {
|
||||||
dependsOn(jsonHookPatch)
|
dependsOn(jsonHookPatch)
|
||||||
|
|
||||||
compatibleWith("com.twitter.android")
|
compatibleWith(
|
||||||
|
"com.twitter.android"(
|
||||||
|
// 10.85+ uses Pairip and requires additional changes to work.
|
||||||
|
"10.84.0-release.0",
|
||||||
|
// Confirmed to not show reply ads. Slightly newer versions may also work.
|
||||||
|
"10.60.0-release.0",
|
||||||
|
"10.48.0-release.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
addJsonHook(JsonHook(hookClassDescriptor))
|
addJsonHook(JsonHook(hookClassDescriptor))
|
||||||
|
|||||||
@@ -37,7 +37,13 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
|||||||
sharedExtensionPatch,
|
sharedExtensionPatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
compatibleWith("com.twitter.android")
|
compatibleWith(
|
||||||
|
"com.twitter.android"(
|
||||||
|
"10.84.0-release.0",
|
||||||
|
"10.60.0-release.0",
|
||||||
|
"10.48.0-release.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val domainName by stringOption(
|
val domainName by stringOption(
|
||||||
key = "domainName",
|
key = "domainName",
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ val sanitizeSharingLinksPatch = bytecodePatch(
|
|||||||
name = "Sanitize sharing links",
|
name = "Sanitize sharing links",
|
||||||
description = "Removes the tracking query parameters from links before they are shared.",
|
description = "Removes the tracking query parameters from links before they are shared.",
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.twitter.android")
|
compatibleWith(
|
||||||
|
"com.twitter.android"(
|
||||||
|
"10.84.0-release.0",
|
||||||
|
"10.60.0-release.0",
|
||||||
|
"10.48.0-release.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
sanitizeSharingLinksFingerprint.method.addInstructions(
|
sanitizeSharingLinksFingerprint.method.addInstructions(
|
||||||
|
|||||||
@@ -82,9 +82,8 @@ val hideAdsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,8 @@ val hideGetPremiumPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ val videoAdsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -57,9 +57,8 @@ val copyVideoUrlPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ val removeViewerDiscretionDialogPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -72,9 +72,8 @@ val downloadsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
|||||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/youtube/patches/DisablePreciseSeekingGesturePatch;"
|
||||||
|
|
||||||
val disablePreciseSeekingGesturePatch = bytecodePatch(
|
val disablePreciseSeekingGesturePatch = bytecodePatch(
|
||||||
name = "Disable precise seeking gesture",
|
|
||||||
description = "Adds an option to disable precise seeking when swiping up on the seekbar.",
|
description = "Adds an option to disable precise seeking when swiping up on the seekbar.",
|
||||||
) {
|
) {
|
||||||
dependsOn(
|
dependsOn(
|
||||||
@@ -21,26 +23,12 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
|
|||||||
addResourcesPatch,
|
addResourcesPatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
compatibleWith(
|
|
||||||
"com.google.android.youtube"(
|
|
||||||
"19.16.39",
|
|
||||||
"19.25.37",
|
|
||||||
"19.34.42",
|
|
||||||
"19.43.41",
|
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
addResources("youtube", "interaction.seekbar.disablePreciseSeekingGesturePatch")
|
addResources("youtube", "interaction.seekbar.disablePreciseSeekingGesturePatch")
|
||||||
|
|
||||||
PreferenceScreen.SEEKBAR.addPreferences(
|
PreferenceScreen.SEEKBAR.addPreferences(
|
||||||
SwitchPreference("revanced_disable_precise_seeking_gesture"),
|
SwitchPreference("revanced_disable_precise_seeking_gesture"),
|
||||||
)
|
)
|
||||||
val extensionMethodDescriptor =
|
|
||||||
"Lapp/revanced/extension/youtube/patches/DisablePreciseSeekingGesturePatch;"
|
|
||||||
|
|
||||||
allowSwipingUpGestureFingerprint.match(
|
allowSwipingUpGestureFingerprint.match(
|
||||||
swipingUpGestureParentFingerprint.originalClassDef,
|
swipingUpGestureParentFingerprint.originalClassDef,
|
||||||
@@ -48,7 +36,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
|
|||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
invoke-static { }, $extensionMethodDescriptor->isGestureDisabled()Z
|
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->isGestureDisabled()Z
|
||||||
move-result v0
|
move-result v0
|
||||||
if-eqz v0, :disabled
|
if-eqz v0, :disabled
|
||||||
return-void
|
return-void
|
||||||
@@ -63,7 +51,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
|
|||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
invoke-static { }, $extensionMethodDescriptor->isGestureDisabled()Z
|
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->isGestureDisabled()Z
|
||||||
move-result v0
|
move-result v0
|
||||||
if-eqz v0, :disabled
|
if-eqz v0, :disabled
|
||||||
const/4 v0, 0x0
|
const/4 v0, 0x0
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
|||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
val enableSeekbarTappingPatch = bytecodePatch(
|
val enableSeekbarTappingPatch = bytecodePatch(
|
||||||
name = "Enable tap to seek",
|
|
||||||
description = "Adds an option to enable tap to seek on the seekbar of the video player.",
|
description = "Adds an option to enable tap to seek on the seekbar of the video player.",
|
||||||
) {
|
) {
|
||||||
dependsOn(
|
dependsOn(
|
||||||
@@ -24,18 +23,6 @@ val enableSeekbarTappingPatch = bytecodePatch(
|
|||||||
addResourcesPatch,
|
addResourcesPatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
compatibleWith(
|
|
||||||
"com.google.android.youtube"(
|
|
||||||
"19.16.39",
|
|
||||||
"19.25.37",
|
|
||||||
"19.34.42",
|
|
||||||
"19.43.41",
|
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
addResources("youtube", "interaction.seekbar.enableSeekbarTappingPatch")
|
addResources("youtube", "interaction.seekbar.enableSeekbarTappingPatch")
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ import com.android.tools.smali.dexlib2.Opcode
|
|||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
internal const val EXTENSION_METHOD_DESCRIPTOR =
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/SlideToSeekPatch;"
|
||||||
"Lapp/revanced/extension/youtube/patches/SlideToSeekPatch;->isSlideToSeekDisabled(Z)Z"
|
|
||||||
|
|
||||||
val enableSlideToSeekPatch = bytecodePatch(
|
val enableSlideToSeekPatch = bytecodePatch(
|
||||||
name = "Enable slide to seek",
|
|
||||||
description = "Adds an option to enable slide to seek " +
|
description = "Adds an option to enable slide to seek " +
|
||||||
"instead of playing at 2x speed when pressing and holding in the video player."
|
"instead of playing at 2x speed when pressing and holding in the video player."
|
||||||
) {
|
) {
|
||||||
@@ -33,18 +31,6 @@ val enableSlideToSeekPatch = bytecodePatch(
|
|||||||
versionCheckPatch,
|
versionCheckPatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
compatibleWith(
|
|
||||||
"com.google.android.youtube"(
|
|
||||||
"19.16.39",
|
|
||||||
"19.25.37",
|
|
||||||
"19.34.42",
|
|
||||||
"19.43.41",
|
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
addResources("youtube", "interaction.seekbar.enableSlideToSeekPatch")
|
addResources("youtube", "interaction.seekbar.enableSlideToSeekPatch")
|
||||||
|
|
||||||
@@ -60,6 +46,8 @@ val enableSlideToSeekPatch = bytecodePatch(
|
|||||||
val checkReference = slideToSeekFingerprint.method.getInstruction(checkIndex)
|
val checkReference = slideToSeekFingerprint.method.getInstruction(checkIndex)
|
||||||
.getReference<MethodReference>()!!
|
.getReference<MethodReference>()!!
|
||||||
|
|
||||||
|
val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->isSlideToSeekDisabled(Z)Z"
|
||||||
|
|
||||||
// A/B check method was only called on this class.
|
// A/B check method was only called on this class.
|
||||||
slideToSeekFingerprint.classDef.methods.forEach { method ->
|
slideToSeekFingerprint.classDef.methods.forEach { method ->
|
||||||
method.findInstructionIndicesReversed {
|
method.findInstructionIndicesReversed {
|
||||||
@@ -71,7 +59,7 @@ val enableSlideToSeekPatch = bytecodePatch(
|
|||||||
addInstructions(
|
addInstructions(
|
||||||
index + 2,
|
index + 2,
|
||||||
"""
|
"""
|
||||||
invoke-static { v$register }, $EXTENSION_METHOD_DESCRIPTOR
|
invoke-static { v$register }, $extensionMethodDescriptor
|
||||||
move-result v$register
|
move-result v$register
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
@@ -96,7 +84,7 @@ val enableSlideToSeekPatch = bytecodePatch(
|
|||||||
addInstructions(
|
addInstructions(
|
||||||
targetIndex + 1,
|
targetIndex + 1,
|
||||||
"""
|
"""
|
||||||
invoke-static { v$targetRegister }, $EXTENSION_METHOD_DESCRIPTOR
|
invoke-static { v$targetRegister }, $extensionMethodDescriptor
|
||||||
move-result v$targetRegister
|
move-result v$targetRegister
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
@@ -110,7 +98,7 @@ val enableSlideToSeekPatch = bytecodePatch(
|
|||||||
addInstructions(
|
addInstructions(
|
||||||
insertIndex,
|
insertIndex,
|
||||||
"""
|
"""
|
||||||
invoke-static { v$targetRegister }, $EXTENSION_METHOD_DESCRIPTOR
|
invoke-static { v$targetRegister }, $extensionMethodDescriptor
|
||||||
move-result v$targetRegister
|
move-result v$targetRegister
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package app.revanced.patches.youtube.interaction.seekbar
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
|
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.seekbarColorPatch
|
||||||
|
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.youtube.shared.seekbarFingerprint
|
||||||
|
import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint
|
||||||
|
|
||||||
|
val hideSeekbarPatch = bytecodePatch(
|
||||||
|
description = "Adds an option to hide the seekbar.",
|
||||||
|
) {
|
||||||
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
settingsPatch,
|
||||||
|
seekbarColorPatch,
|
||||||
|
addResourcesPatch,
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
addResources("youtube", "layout.hide.seekbar.hideSeekbarPatch")
|
||||||
|
|
||||||
|
PreferenceScreen.SEEKBAR.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_seekbar"),
|
||||||
|
SwitchPreference("revanced_hide_seekbar_thumbnail"),
|
||||||
|
)
|
||||||
|
|
||||||
|
seekbarOnDrawFingerprint.match(seekbarFingerprint.originalClassDef).method.addInstructionsWithLabels(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
const/4 v0, 0x0
|
||||||
|
invoke-static { }, Lapp/revanced/extension/youtube/patches/HideSeekbarPatch;->hideSeekbar()Z
|
||||||
|
move-result v0
|
||||||
|
if-eqz v0, :hide_seekbar
|
||||||
|
return-void
|
||||||
|
:hide_seekbar
|
||||||
|
nop
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package app.revanced.patches.youtube.interaction.seekbar
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val seekbarPatch = bytecodePatch(
|
||||||
|
name = "Seekbar",
|
||||||
|
description = "Adds options to disable precise seeking when swiping up on the seekbar, " +
|
||||||
|
"slide to seek instead of playing at 2x speed when pressing and holding, " +
|
||||||
|
"tapping the player seekbar to seek, " +
|
||||||
|
"and hiding the video player seekbar."
|
||||||
|
) {
|
||||||
|
dependsOn(
|
||||||
|
disablePreciseSeekingGesturePatch,
|
||||||
|
enableSlideToSeekPatch,
|
||||||
|
enableSeekbarTappingPatch,
|
||||||
|
hideSeekbarPatch,
|
||||||
|
seekbarThumbnailsPatch
|
||||||
|
)
|
||||||
|
|
||||||
|
compatibleWith(
|
||||||
|
"com.google.android.youtube"(
|
||||||
|
"19.16.39",
|
||||||
|
"19.25.37",
|
||||||
|
"19.34.42",
|
||||||
|
"19.43.41",
|
||||||
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
|||||||
import app.revanced.patches.youtube.layout.seekbar.fullscreenSeekbarThumbnailsFingerprint
|
import app.revanced.patches.youtube.layout.seekbar.fullscreenSeekbarThumbnailsFingerprint
|
||||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater
|
import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater
|
||||||
|
import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater
|
||||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||||
|
|
||||||
@@ -17,7 +18,6 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
|||||||
"Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;"
|
"Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;"
|
||||||
|
|
||||||
val seekbarThumbnailsPatch = bytecodePatch(
|
val seekbarThumbnailsPatch = bytecodePatch(
|
||||||
name = "Seekbar thumbnails",
|
|
||||||
description = "Adds an option to use high quality fullscreen seekbar thumbnails. " +
|
description = "Adds an option to use high quality fullscreen seekbar thumbnails. " +
|
||||||
"Patching 19.16.39 adds an option to restore old seekbar thumbnails.",
|
"Patching 19.16.39 adds an option to restore old seekbar thumbnails.",
|
||||||
) {
|
) {
|
||||||
@@ -27,19 +27,13 @@ val seekbarThumbnailsPatch = bytecodePatch(
|
|||||||
versionCheckPatch,
|
versionCheckPatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
compatibleWith(
|
|
||||||
"com.google.android.youtube"(
|
|
||||||
"19.16.39",
|
|
||||||
"19.25.37",
|
|
||||||
"19.34.42",
|
|
||||||
"19.43.41",
|
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
if (is_20_09_or_greater) {
|
||||||
|
// High quality seekbar thumbnails is partially broken in 20.09
|
||||||
|
// and the code is completely removed in 20.10+
|
||||||
|
return@execute
|
||||||
|
}
|
||||||
|
|
||||||
addResources("youtube", "layout.seekbar.seekbarThumbnailsPatch")
|
addResources("youtube", "layout.seekbar.seekbarThumbnailsPatch")
|
||||||
|
|
||||||
if (is_19_17_or_greater) {
|
if (is_19_17_or_greater) {
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ private val swipeControlsResourcePatch = resourcePatch {
|
|||||||
TextPreference("revanced_swipe_overlay_background_opacity", inputType = InputType.NUMBER),
|
TextPreference("revanced_swipe_overlay_background_opacity", inputType = InputType.NUMBER),
|
||||||
TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER),
|
TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER),
|
||||||
TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER),
|
TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER),
|
||||||
|
TextPreference("revanced_swipe_volume_sensitivity", inputType = InputType.NUMBER),
|
||||||
)
|
)
|
||||||
|
|
||||||
copyResources(
|
copyResources(
|
||||||
@@ -84,9 +85,8 @@ val swipeControlsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ val swipeControlsPatch = bytecodePatch(
|
|||||||
// region patch to enable/disable swipe to change video.
|
// region patch to enable/disable swipe to change video.
|
||||||
|
|
||||||
if (is_19_43_or_greater) {
|
if (is_19_43_or_greater) {
|
||||||
swipeChangeVideoFingerprint.method.insertFeatureFlagBooleanOverride(
|
swipeChangeVideoFingerprint.method.insertLiteralOverride(
|
||||||
SWIPE_CHANGE_VIDEO_FEATURE_FLAG,
|
SWIPE_CHANGE_VIDEO_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->allowSwipeChangeVideo(Z)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->allowSwipeChangeVideo(Z)Z"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ val autoCaptionsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -47,9 +47,8 @@ val customBrandingPatch = resourcePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,8 @@ val changeHeaderPatch = resourcePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ val hideButtonsPatch = resourcePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
|||||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
import app.revanced.util.insertFeatureFlagBooleanOverride
|
import app.revanced.util.insertLiteralOverride
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
@@ -44,9 +44,8 @@ val navigationButtonsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -120,17 +119,17 @@ val navigationButtonsPatch = bytecodePatch(
|
|||||||
|
|
||||||
// Force on/off translucent effect on status bar and navigation buttons.
|
// Force on/off translucent effect on status bar and navigation buttons.
|
||||||
if (is_19_25_or_greater) {
|
if (is_19_25_or_greater) {
|
||||||
translucentNavigationStatusBarFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride(
|
translucentNavigationStatusBarFeatureFlagFingerprint.method.insertLiteralOverride(
|
||||||
TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG,
|
TRANSLUCENT_NAVIGATION_STATUS_BAR_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationStatusBar(Z)Z",
|
"$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationStatusBar(Z)Z",
|
||||||
)
|
)
|
||||||
|
|
||||||
translucentNavigationButtonsFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride(
|
translucentNavigationButtonsFeatureFlagFingerprint.method.insertLiteralOverride(
|
||||||
TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG,
|
TRANSLUCENT_NAVIGATION_BUTTONS_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z",
|
"$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z",
|
||||||
)
|
)
|
||||||
|
|
||||||
translucentNavigationButtonsSystemFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride(
|
translucentNavigationButtonsSystemFeatureFlagFingerprint.method.insertLiteralOverride(
|
||||||
TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG,
|
TRANSLUCENT_NAVIGATION_BUTTONS_SYSTEM_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z",
|
"$EXTENSION_CLASS_DESCRIPTOR->useTranslucentNavigationButtons(Z)Z",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -58,9 +58,8 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,8 @@ val changeFormFactorPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -63,9 +63,8 @@ val hideEndscreenCardsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,8 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,8 @@ val disableFullscreenAmbientModePatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,21 @@ internal val hideShowMoreButtonFingerprint = fingerprint {
|
|||||||
literal { expandButtonDownId }
|
literal { expandButtonDownId }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 20.07+
|
||||||
|
*/
|
||||||
internal val parseElementFromBufferFingerprint = fingerprint {
|
internal val parseElementFromBufferFingerprint = fingerprint {
|
||||||
|
parameters("L", "L", "[B", "L", "L")
|
||||||
|
opcodes(
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IGET_BOOLEAN,
|
||||||
|
Opcode.INVOKE_INTERFACE,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
)
|
||||||
|
strings("Failed to parse Element") // String is a partial match.
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val parseElementFromBufferLegacyFingerprint = fingerprint {
|
||||||
parameters("L", "L", "[B", "L", "L")
|
parameters("L", "L", "[B", "L", "L")
|
||||||
opcodes(
|
opcodes(
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
@@ -110,7 +124,6 @@ internal val showFloatingMicrophoneButtonFingerprint = fingerprint {
|
|||||||
opcodes(
|
opcodes(
|
||||||
Opcode.IGET_BOOLEAN,
|
Opcode.IGET_BOOLEAN,
|
||||||
Opcode.IF_EQZ,
|
Opcode.IF_EQZ,
|
||||||
Opcode.RETURN_VOID,
|
|
||||||
)
|
)
|
||||||
literal { fabButtonId }
|
literal { fabButtonId }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ import app.revanced.patches.shared.misc.settings.preference.*
|
|||||||
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
|
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
|
||||||
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
|
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
|
||||||
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
|
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
|
||||||
import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater
|
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
|
||||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||||
|
import app.revanced.util.findFreeRegister
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
@@ -120,7 +122,6 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
|||||||
addResourcesPatch,
|
addResourcesPatch,
|
||||||
hideLayoutComponentsResourcePatch,
|
hideLayoutComponentsResourcePatch,
|
||||||
navigationBarHookPatch,
|
navigationBarHookPatch,
|
||||||
versionCheckPatch
|
|
||||||
)
|
)
|
||||||
|
|
||||||
compatibleWith(
|
compatibleWith(
|
||||||
@@ -129,9 +130,8 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -142,6 +142,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
|||||||
PreferenceScreenPreference(
|
PreferenceScreenPreference(
|
||||||
key = "revanced_hide_description_components_screen",
|
key = "revanced_hide_description_components_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
|
SwitchPreference("revanced_hide_ai_generated_video_summary_section"),
|
||||||
SwitchPreference("revanced_hide_attributes_section"),
|
SwitchPreference("revanced_hide_attributes_section"),
|
||||||
SwitchPreference("revanced_hide_chapters_section"),
|
SwitchPreference("revanced_hide_chapters_section"),
|
||||||
SwitchPreference("revanced_hide_info_cards_section"),
|
SwitchPreference("revanced_hide_info_cards_section"),
|
||||||
@@ -154,7 +155,8 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
|||||||
PreferenceScreenPreference(
|
PreferenceScreenPreference(
|
||||||
"revanced_comments_screen",
|
"revanced_comments_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_hide_comments_chat_summary"),
|
SwitchPreference("revanced_hide_comments_ai_chat_summary"),
|
||||||
|
SwitchPreference("revanced_hide_comments_ai_summary"),
|
||||||
SwitchPreference("revanced_hide_comments_by_members_header"),
|
SwitchPreference("revanced_hide_comments_by_members_header"),
|
||||||
SwitchPreference("revanced_hide_comments_section"),
|
SwitchPreference("revanced_hide_comments_section"),
|
||||||
SwitchPreference("revanced_hide_comments_create_a_short_button"),
|
SwitchPreference("revanced_hide_comments_create_a_short_button"),
|
||||||
@@ -245,29 +247,31 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
|||||||
|
|
||||||
// region Mix playlists
|
// region Mix playlists
|
||||||
|
|
||||||
parseElementFromBufferFingerprint.method.apply {
|
(if (is_20_07_or_greater) parseElementFromBufferFingerprint
|
||||||
val startIndex = parseElementFromBufferFingerprint.patternMatch!!.startIndex
|
else parseElementFromBufferLegacyFingerprint).let {
|
||||||
// Target code is a mess with a lot of register moves.
|
it.method.apply {
|
||||||
// There is no simple way to find a free register for all versions so this is hard coded.
|
val byteArrayParameter = "p3"
|
||||||
val freeRegister = if (is_19_47_or_greater) 6 else 0
|
val startIndex = it.patternMatch!!.startIndex
|
||||||
val byteArrayParameter = "p3"
|
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
|
||||||
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
|
val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC }
|
||||||
val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC }
|
val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC
|
||||||
val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC
|
val insertIndex = startIndex + 1
|
||||||
|
val freeRegister = findFreeRegister(insertIndex, conversionContextRegister, returnEmptyComponentRegister)
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
startIndex + 1,
|
insertIndex,
|
||||||
"""
|
"""
|
||||||
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
|
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
|
||||||
move-result v$freeRegister
|
move-result v$freeRegister
|
||||||
if-eqz v$freeRegister, :show
|
if-eqz v$freeRegister, :show
|
||||||
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
|
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
|
||||||
goto :return_empty_component
|
goto :return_empty_component
|
||||||
:show
|
:show
|
||||||
const/4 v$freeRegister, 0x0 # Restore register, required for 19.16
|
nop
|
||||||
""",
|
""",
|
||||||
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
|
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@@ -343,19 +347,18 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
|||||||
|
|
||||||
// region hide floating microphone
|
// region hide floating microphone
|
||||||
|
|
||||||
showFloatingMicrophoneButtonFingerprint.let {
|
showFloatingMicrophoneButtonFingerprint.method.apply {
|
||||||
it.method.apply {
|
val literalIndex = indexOfFirstLiteralInstructionOrThrow(fabButtonId)
|
||||||
val startIndex = it.patternMatch!!.startIndex
|
val booleanIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.IGET_BOOLEAN)
|
||||||
val register = getInstruction<TwoRegisterInstruction>(startIndex).registerA
|
val register = getInstruction<TwoRegisterInstruction>(booleanIndex).registerA
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
startIndex + 1,
|
booleanIndex + 1,
|
||||||
"""
|
"""
|
||||||
invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideFloatingMicrophoneButton(Z)Z
|
invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideFloatingMicrophoneButton(Z)Z
|
||||||
move-result v$register
|
move-result v$register
|
||||||
""",
|
"""
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
@@ -61,9 +61,8 @@ val hideInfoCardsPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,8 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
|
|||||||
"19.25.37",
|
"19.25.37",
|
||||||
"19.34.42",
|
"19.34.42",
|
||||||
"19.43.41",
|
"19.43.41",
|
||||||
"19.45.38",
|
|
||||||
"19.46.42",
|
|
||||||
"19.47.53",
|
"19.47.53",
|
||||||
|
"20.07.39",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,7 +51,10 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
|
|||||||
SwitchPreference("revanced_hide_player_flyout_speed"),
|
SwitchPreference("revanced_hide_player_flyout_speed"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_lock_screen"),
|
SwitchPreference("revanced_hide_player_flyout_lock_screen"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_more_info"),
|
SwitchPreference("revanced_hide_player_flyout_more_info"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_audio_track"),
|
SwitchPreference(
|
||||||
|
key = "revanced_hide_player_flyout_audio_track",
|
||||||
|
tag = "app.revanced.extension.youtube.settings.preference.HideAudioFlyoutMenuPreference"
|
||||||
|
),
|
||||||
SwitchPreference("revanced_hide_player_flyout_watch_in_vr"),
|
SwitchPreference("revanced_hide_player_flyout_watch_in_vr"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_sleep_timer"),
|
SwitchPreference("revanced_hide_player_flyout_sleep_timer"),
|
||||||
SwitchPreference("revanced_hide_player_flyout_video_quality_footer"),
|
SwitchPreference("revanced_hide_player_flyout_video_quality_footer"),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user