Compare commits

..

51 Commits

Author SHA1 Message Date
semantic-release-bot
0572d48fde chore: Release v5.18.1-dev.2 [skip ci]
## [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)) ([37984b8](37984b8b99))
2025-04-01 19:00:31 +00:00
LisoUseInAIKyrios
37984b8b99 fix(YouTube): Combine multiple seekbar patches into a single patch (#4705) 2025-04-01 20:57:03 +02:00
github-actions[bot]
6e63193f06 chore: Sync translations (#4713) 2025-04-01 20:51:16 +02:00
LisoUseInAIKyrios
b2384b22a5 refactor: Add more opcodes to findFreeRegister 2025-04-01 20:17:00 +02:00
semantic-release-bot
ccb76983ff chore: Release v5.18.1-dev.1 [skip ci]
## [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 ([318b55b](318b55b8fe))
2025-03-31 13:45:18 +00:00
LisoUseInAIKyrios
318b55b8fe fix(YouTube - Remove background playback restrictions): Do not show media controls when playing Shorts from the feed 2025-03-31 15:36:01 +02:00
github-actions[bot]
49ade9efbc chore: Sync translations (#4703) 2025-03-31 15:35:28 +02:00
LisoUseInAIKyrios
d77515bd68 refactor: Add helper method to find a free register for a specific insert index (#4693) 2025-03-30 18:37:54 +02:00
semantic-release-bot
087bf1e152 chore: Release v5.18.0 [skip ci]
# [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](84f585492e))

### Features

* **YouTube:** Support version `20.07.39` ([#4677](https://github.com/ReVanced/revanced-patches/issues/4677)) ([842ba4f](842ba4fc4d))
2025-03-28 18:51:44 +00:00
LisoUseInAIKyrios
c2994d583d chore: Merge branch dev to main (#4686) 2025-03-28 19:48:32 +01:00
semantic-release-bot
127b0a63fe chore: Release v5.18.0-dev.2 [skip ci]
# [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](84f585492e))
2025-03-28 18:36:38 +00:00
github-actions[bot]
27aafd0ee1 chore: Sync translations (#4689) 2025-03-28 19:31:52 +01:00
semantic-release-bot
49c54c0e54 chore: Release v5.18.0-dev.1 [skip ci]
# [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)) ([842ba4f](842ba4fc4d))
2025-03-28 17:01:42 +00:00
LisoUseInAIKyrios
842ba4fc4d feat(YouTube): Support version 20.07.39 (#4677) 2025-03-28 17:49:12 +01:00
semantic-release-bot
66ecadce4f chore: Release v5.17.0 [skip ci]
# [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)) ([4d910fe](4d910fea93))
* **Spotify - Unlock Premium:** Override additional attributes ([#4651](https://github.com/ReVanced/revanced-patches/issues/4651)) ([ca4f960](ca4f960171))
* **Spotify - Unlock Premium:** Use correct patch description convention ([a486522](a4865228f8))
* **X / Twitter:** Constrain patches to latest compatible versions ([#4683](https://github.com/ReVanced/revanced-patches/issues/4683)) ([497291c](497291c478))
* **YouTube - Navigation buttons:** Add user dialog message to 'Disable translucent status bar' ([bf91e12](bf91e127d8))

### Features

* **Spotify - Unlock Premium:** Disable the "Spotify Premium" upsell experiment in context menus ([c84be12](c84be120bd))
2025-03-28 16:39:31 +00:00
LisoUseInAIKyrios
73ca04da5e chore: Merge branch dev to main (#4658) 2025-03-28 17:36:31 +01:00
semantic-release-bot
a5d26208c1 chore: Release v5.17.0-dev.4 [skip ci]
# [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)) ([497291c](497291c478))
2025-03-28 16:14:49 +00:00
LisoUseInAIKyrios
497291c478 fix(X / Twitter): Constrain patches to latest compatible versions (#4683) 2025-03-28 17:11:30 +01:00
github-actions[bot]
b24278a544 chore: Sync translations (#4680) 2025-03-28 15:03:07 +01:00
semantic-release-bot
135f9ead3c chore: Release v5.17.0-dev.3 [skip ci]
# [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)) ([ca4f960](ca4f960171))
2025-03-28 10:55:04 +00:00
xC3FFF0E
ca4f960171 fix(Spotify - Unlock Premium): Override additional attributes (#4651)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-03-28 11:52:23 +01:00
semantic-release-bot
7f228cc535 chore: Release v5.17.0-dev.2 [skip ci]
# [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' ([bf91e12](bf91e127d8))
2025-03-27 19:23:17 +00:00
LisoUseInAIKyrios
bf91e127d8 fix(YouTube - Navigation buttons): Add user dialog message to 'Disable translucent status bar' 2025-03-27 20:20:05 +01:00
semantic-release-bot
f07fc1ad93 chore: Release v5.17.0-dev.1 [skip ci]
# [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](a4865228f8))

### Features

* **Spotify - Unlock Premium:** Disable the "Spotify Premium" upsell experiment in context menus ([c84be12](c84be120bd))
2025-03-27 00:48:00 +00:00
oSumAtrIX
c84be120bd feat(Spotify - Unlock Premium): Disable the "Spotify Premium" upsell experiment in context menus 2025-03-27 01:40:54 +01:00
semantic-release-bot
e67f390e2b chore: Release v5.16.2-dev.1 [skip ci]
## [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)) ([4d910fe](4d910fea93))
2025-03-26 18:34:18 +00:00
LisoUseInAIKyrios
4d910fea93 fix(Facebook - Hide 'Sponsored Stories'): Constrain patch to latest compatible version (#4657) 2025-03-26 19:30:48 +01:00
semantic-release-bot
72adbe5519 chore: Release v5.16.1 [skip ci]
## [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](06be36cddf))
2025-03-26 14:10:25 +00:00
oSumAtrIX
54d49b774e chore: Merge branch dev to main (#4650) 2025-03-26 15:08:18 +01:00
semantic-release-bot
283bb31567 chore: Release v5.16.1-dev.1 [skip ci]
## [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](06be36cddf))
2025-03-26 13:54:23 +00:00
semantic-release-bot
2724fcbd27 chore: Release v5.16.0 [skip ci]
# [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+ ([54eef22](54eef22ce7))

### Features

* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([5c5a1e4](5c5a1e4b8b))
* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([d5845ab](d5845abd08))
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([d8c276c](d8c276cf96))
2025-03-26 03:42:23 +00:00
oSumAtrIX
7c28193579 chore: Merge branch dev to main (#4628)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: ILoveOpenSourceApplications <117499019+ILoveOpenSourceApplications@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: Brosssh <tiabroch@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-26 04:39:27 +01:00
github-actions[bot]
cd1ee814c4 chore: Sync translations (#4645) 2025-03-26 04:30:29 +01:00
semantic-release-bot
d9ccd73b5f chore: Release v5.16.0-dev.2 [skip ci]
# [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)) ([5c5a1e4](5c5a1e4b8b))
2025-03-26 03:27:26 +00:00
oSumAtrIX
5c5a1e4b8b feat(Spotify): Add Unlock premium patch (#4644)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: Brosssh <tiabroch@gmail.com>
2025-03-26 04:24:47 +01:00
semantic-release-bot
66a2ee2416 chore: Release v5.16.0-dev.1 [skip ci]
# [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+ ([54eef22](54eef22ce7))

### Features

* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([d5845ab](d5845abd08))
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([d8c276c](d8c276cf96))
2025-03-24 16:26:47 +00:00
ILoveOpenSourceApplications
d8c276cf96 feat(YouTube - Video description): Add Hide AI-generated video summary (#4636) 2025-03-24 17:23:57 +01:00
ILoveOpenSourceApplications
d5845abd08 feat(YouTube - Comments): Add Hide AI Comments summary (#4634) 2025-03-24 17:23:12 +01:00
LisoUseInAIKyrios
54eef22ce7 fix(YouTube - Settings): System navigation bar is located above the settings ui on Android 15+ 2025-03-24 17:21:36 +01:00
ILoveOpenSourceApplications
e287bdc59d chore(YouTube): Use consistent strings (#4637) 2025-03-24 17:12:11 +01:00
LisoUseInAIKyrios
20a82ef956 chore: Remove duplicate language entry 2025-03-22 11:01:19 +01:00
semantic-release-bot
1e29da9e06 chore: Release v5.15.0 [skip ci]
# [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 ([54a7afa](54a7afa540))
* **YouTube - Spoof app version:** Remove broken spoof targets that YouTube no longer supports ([#4610](https://github.com/ReVanced/revanced-patches/issues/4610)) ([04a1700](04a170054e))
* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([df838ed](df838ed91d))

### Features

* **YouTube - SponsorBlock:** Add opacity setting to category segment colors ([#4582](https://github.com/ReVanced/revanced-patches/issues/4582)) ([bbf3a34](bbf3a34a2f))
2025-03-21 10:54:27 +00:00
LisoUseInAIKyrios
56e6a90a90 chore: Merge branch dev to main (#4615) 2025-03-21 11:51:03 +01:00
semantic-release-bot
76d32e21c2 chore: Release v5.15.0-dev.4 [skip ci]
# [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 ([54a7afa](54a7afa540))
2025-03-21 09:26:53 +00:00
LisoUseInAIKyrios
54a7afa540 fix(YouTube - Spoof app version): Change oldest spoof target to 19.01.34 2025-03-21 10:23:26 +01:00
LisoUseInAIKyrios
ef86438bac ci: Pull Crowdin strings less often 2025-03-21 10:21:16 +01:00
github-actions[bot]
0683cedac0 chore: Sync translations (#4626) 2025-03-21 10:18:28 +01:00
semantic-release-bot
35753410aa chore: Release v5.15.0-dev.3 [skip ci]
# [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)

### Bug Fixes

* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([df838ed](df838ed91d))
2025-03-20 11:17:31 +00:00
LisoUseInAIKyrios
df838ed91d fix(YouTube): Do not show restart prompt more than once if setting change is canceled 2025-03-20 12:14:31 +01:00
github-actions[bot]
8e494d26d4 chore: Sync translations (#4623) 2025-03-20 12:08:20 +01:00
LisoUseInAIKyrios
7d834e5421 refactor(YouTube - Spoof app version): Allow manually spoofing to 19.01 - 19.25 2025-03-20 09:57:29 +01:00
190 changed files with 2759 additions and 1640 deletions

View File

@@ -2,7 +2,7 @@ name: Pull strings
on:
schedule:
- cron: "0 */8 * * *"
- cron: "0 */12 * * *"
workflow_dispatch:
jobs:

View File

@@ -1,3 +1,175 @@
## [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)
### Bug Fixes
* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([49797fe](https://github.com/ReVanced/revanced-patches/commit/49797fe8d0c4a0981ef621a31356c4315ae3777b))
# [5.15.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.1...v5.15.0-dev.2) (2025-03-19)

View File

@@ -22,12 +22,23 @@ import app.revanced.extension.shared.settings.Setting;
@SuppressWarnings("deprecation")
public abstract class AbstractPreferenceFragment extends PreferenceFragment {
/**
* Indicates that if a preference changes,
* to apply the change from the Setting to the UI component.
*/
public static boolean settingImportInProgress;
/**
* Prevents recursive calls during preference <-> UI syncing from showing extra dialogs.
*/
private static boolean updatingPreference;
/**
* Used to prevent showing reboot dialog, if user cancels a setting user dialog.
*/
private static boolean showingUserDialogMessage;
/**
* Confirm and restart dialog button text and title.
* Set by subclasses if Strings cannot be added as a resource.
@@ -35,13 +46,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
@Nullable
protected static String restartDialogButtonText, restartDialogTitle, confirmDialogTitle;
/**
* Used to prevent showing reboot dialog, if user cancels a setting user dialog.
*/
private boolean showingUserDialogMessage;
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
try {
if (updatingPreference) {
Logger.printDebug(() -> "Ignoring preference change as sync is in progress");
return;
}
Setting<?> setting = Setting.getSettingFromPath(Objects.requireNonNull(str));
if (setting == null) {
return;
@@ -63,10 +74,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
}
}
updatingPreference = true;
// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
// Updating here can can cause a recursive call back into this same method.
updatePreference(pref, setting, true, settingImportInProgress);
// Update any other preference availability that may now be different.
updateUIAvailability();
updatingPreference = false;
} catch (Exception ex) {
Logger.printException(() -> "OnSharedPreferenceChangeListener failure", ex);
}
@@ -97,7 +111,9 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
if (confirmDialogTitle == null) {
confirmDialogTitle = str("revanced_settings_confirm_user_dialog_title");
}
showingUserDialogMessage = true;
new AlertDialog.Builder(context)
.setTitle(confirmDialogTitle)
.setMessage(Objects.requireNonNull(setting.userDialogMessage).toString())
@@ -141,14 +157,16 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
* @return If the preference is currently set to the default value of the Setting.
*/
protected boolean prefIsSetToDefault(Preference pref, Setting<?> setting) {
Object defaultValue = setting.defaultValue;
if (pref instanceof SwitchPreference switchPref) {
return switchPref.isChecked() == (Boolean) setting.defaultValue;
return switchPref.isChecked() == (Boolean) defaultValue;
}
String defaultValueString = defaultValue.toString();
if (pref instanceof EditTextPreference editPreference) {
return editPreference.getText().equals(setting.defaultValue.toString());
return editPreference.getText().equals(defaultValueString);
}
if (pref instanceof ListPreference listPref) {
return listPref.getValue().equals(setting.defaultValue.toString());
return listPref.getValue().equals(defaultValueString);
}
throw new IllegalStateException("Must override method to handle "
@@ -255,7 +273,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
}
}
public static void showRestartDialog(@NonNull final Context context) {
public static void showRestartDialog(Context context) {
Utils.verifyOnMainThread();
if (restartDialogTitle == null) {
restartDialogTitle = str("revanced_settings_restart_title");
@@ -263,6 +281,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
if (restartDialogButtonText == null) {
restartDialogButtonText = str("revanced_settings_restart");
}
new AlertDialog.Builder(context)
.setMessage(restartDialogTitle)
.setPositiveButton(restartDialogButtonText, (dialog, id)

View File

@@ -122,6 +122,21 @@ public class SpoofVideoStreamsPatch {
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.
*/

View 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
}
}

View File

@@ -0,0 +1 @@
<manifest/>

View 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
}
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,5 @@
package com.spotify.remoteconfig.internal;
public final class AccountAttribute {
public Object value_;
}

View File

@@ -1,6 +1,7 @@
package app.revanced.extension.youtube.patches;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
import app.revanced.extension.youtube.shared.ShortsPlayerState;
@SuppressWarnings("unused")
@@ -23,7 +24,13 @@ public class BackgroundPlaybackPatch {
// 7. Close the Short
// 8. Resume playing the regular video
// 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;
}
/**

View File

@@ -2,7 +2,7 @@ package app.revanced.extension.youtube.patches;
import app.revanced.extension.youtube.settings.Settings;
/** @noinspection unused*/
@SuppressWarnings("unused")
public class DisableResumingStartupShortsPlayerPatch {
/**
@@ -11,4 +11,11 @@ public class DisableResumingStartupShortsPlayerPatch {
public static boolean disableResumingStartupShortsPlayer() {
return Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
}
/**
* Injection point.
*/
public static boolean disableResumingStartupShortsPlayer(boolean original) {
return original && !Settings.DISABLE_RESUMING_SHORTS_PLAYER.get();
}
}

View File

@@ -43,10 +43,13 @@ public final class MiniplayerPatch {
MODERN_2(null, 2),
MODERN_3(null, 3),
/**
* Half broken miniplayer, that might be work in progress or left over abandoned code.
* Can force this type by editing the import/export settings.
* Works and is functional with 20.03+
*/
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.
@@ -126,12 +129,13 @@ public final class MiniplayerPatch {
private static final boolean DRAG_AND_DROP_ENABLED =
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
private static final boolean HIDE_EXPAND_CLOSE_ENABLED =
Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.get()
&& Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.isAvailable();
private static final boolean HIDE_OVERLAY_BUTTONS_ENABLED =
Settings.MINIPLAYER_HIDE_OVERLAY_BUTTONS.get()
&& Settings.MINIPLAYER_HIDE_OVERLAY_BUTTONS.isAvailable();
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,
// 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());
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 =
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
public boolean isAvailable() {
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
&& !Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get() && !Settings.MINIPLAYER_DRAG_AND_DROP.get())
|| (IS_19_29_OR_GREATER && type == MODERN_3);
@@ -227,9 +232,13 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static void adjustMiniplayerOpacity(ImageView view) {
public static void adjustMiniplayerOpacity(View view) {
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.
*/
public static boolean enableMiniplayerDoubleTapAction(boolean original) {
public static boolean getMiniplayerDoubleTapAction(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
@@ -258,7 +267,7 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static boolean enableMiniplayerDragAndDrop(boolean original) {
public static boolean getMiniplayerDragAndDrop(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
return original;
}
@@ -266,13 +275,36 @@ public final class MiniplayerPatch {
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.
*/
public static boolean setRoundedCorners(boolean original) {
if (CURRENT_TYPE.isModern()) {
return MINIPLAYER_ROUNDED_CORNERS_ENABLED;
public static boolean getHorizontalDrag(boolean original) {
if (CURRENT_TYPE == DEFAULT) {
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;
@@ -281,7 +313,7 @@ public final class MiniplayerPatch {
/**
* Injection point.
*/
public static int setMiniplayerDefaultSize(int original) {
public static int getMiniplayerDefaultSize(int original) {
if (CURRENT_TYPE.isModern()) {
return MINIPLAYER_SIZE;
}
@@ -289,29 +321,26 @@ public final class MiniplayerPatch {
return original;
}
/**
* Injection point.
*/
public static void hideMiniplayerExpandClose(View view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_OVERLAY_BUTTONS_ENABLED, view);
}
/**
* Injection point.
*/
public static boolean setHorizontalDrag(boolean original) {
if (CURRENT_TYPE.isModern()) {
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
public static void hideMiniplayerActionButton(View view) {
if (CURRENT_TYPE == MODERN_4) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_OVERLAY_BUTTONS_ENABLED, view);
}
return original;
}
/**
* Injection point.
*/
public static void hideMiniplayerExpandClose(ImageView view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_EXPAND_CLOSE_ENABLED, view);
}
/**
* Injection point.
*/
public static void hideMiniplayerRewindForward(ImageView view) {
public static void hideMiniplayerRewindForward(View view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_REWIND_FORWARD_ENABLED, view);
}

View File

@@ -3,11 +3,15 @@ package app.revanced.extension.youtube.patches;
import app.revanced.extension.shared.Utils;
public class VersionCheckPatch {
public static final boolean IS_19_17_OR_GREATER = Utils.getAppVersionName().compareTo("19.17.00") >= 0;
public static final boolean IS_19_20_OR_GREATER = Utils.getAppVersionName().compareTo("19.20.00") >= 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_34_OR_GREATER = Utils.getAppVersionName().compareTo("19.34.00") >= 0;
public static final boolean IS_19_46_OR_GREATER = Utils.getAppVersionName().compareTo("19.46.00") >= 0;
private static boolean isVersionOrGreater(String version) {
return Utils.getAppVersionName().compareTo(version) >= 0;
}
public static final boolean IS_19_17_OR_GREATER = isVersionOrGreater("19.17.00");
public static final boolean IS_19_20_OR_GREATER = isVersionOrGreater("19.20.00");
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");
}

View File

@@ -12,10 +12,12 @@ final class CommentsFilter extends Filter {
private final StringFilterGroup commentComposer;
private final ByteArrayFilterGroup emojiPickerBufferGroup;
private final StringFilterGroup filterChipBar;
private final ByteArrayFilterGroup aiCommentsSummary;
public CommentsFilter() {
var chatSummary = new StringFilterGroup(
Settings.HIDE_COMMENTS_CHAT_SUMMARY,
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
"live_chat_summary_banner.eml"
);
@@ -58,6 +60,16 @@ final class CommentsFilter extends Filter {
"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(
chatSummary,
commentsByMembers,
@@ -65,7 +77,8 @@ final class CommentsFilter extends Filter {
createAShort,
previewComment,
thanksButton,
commentComposer
commentComposer,
filterChipBar
);
}
@@ -84,6 +97,13 @@ final class CommentsFilter extends Filter {
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);
}
}

View File

@@ -23,6 +23,11 @@ final class DescriptionComponentsFilter extends Filter {
"metadata"
);
final StringFilterGroup aiGeneratedVideoSummarySection = new StringFilterGroup(
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
"cell_expandable_metadata.eml"
);
final StringFilterGroup attributesSection = new StringFilterGroup(
Settings.HIDE_ATTRIBUTES_SECTION,
"gaming_section",
@@ -67,6 +72,7 @@ final class DescriptionComponentsFilter extends Filter {
);
addPathCallbacks(
aiGeneratedVideoSummarySection,
attributesSection,
infoCardsSection,
howThisWasMadeSection,

View File

@@ -114,7 +114,7 @@ public class ReturnYouTubeDislike {
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;
private static final ShapeDrawable leftSeparatorShape;
@@ -129,7 +129,7 @@ public class ReturnYouTubeDislike {
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3.7f, dp);
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.setBounds(leftSeparatorBounds);
@@ -238,7 +238,7 @@ public class ReturnYouTubeDislike {
String leftSeparatorString = getTextDirectionString();
final Spannable leftSeparatorSpan;
if (isRollingNumber) {
leftSeparatorSpan = new SpannableString(leftSeparatorString);
leftSeparatorSpan = new SpannableString(leftSeparatorString);
} else {
leftSeparatorString += " ";
leftSeparatorSpan = new SpannableString(leftSeparatorString);
@@ -623,7 +623,7 @@ public class ReturnYouTubeDislike {
userVote = vote;
clearUICache();
}
if (future.isDone()) {
// Update the fetched vote data.
RYDVoteData voteData = getFetchData(MAX_MILLISECONDS_TO_BLOCK_UI_WAITING_FOR_FETCH);

View File

@@ -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.ExitFullscreenPatch.FullscreenMode;
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.MiniplayerType;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
@@ -40,6 +39,7 @@ import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrow
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime;
import app.revanced.extension.youtube.patches.MiniplayerPatch;
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
public class Settings extends BaseSettings {
@@ -156,7 +156,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_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_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_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);
@@ -168,7 +168,8 @@ public class Settings extends BaseSettings {
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));
// 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_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);
@@ -176,6 +177,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_THANKS_BUTTON = new BooleanSetting("revanced_hide_comments_thanks_button", TRUE);
// 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_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);
@@ -218,7 +220,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 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 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
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));
@@ -231,7 +233,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 SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true,
"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_DARK = new BooleanSetting("revanced_disable_translucent_navigation_bar_dark", FALSE, true);

View File

@@ -19,7 +19,6 @@ import android.widget.Toolbar;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
@@ -139,11 +138,13 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
.findViewById(android.R.id.content)
.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) {
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
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;
});
}

View File

@@ -73,6 +73,7 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
if (currentClientType == clientType) {
return;
}
currentClientType = clientType;
Logger.printDebug(() -> "Updating spoof stream side effects preference");
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());

View File

@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
org.gradle.parallel = true
android.useAndroidX = true
kotlin.code.style = official
version = 5.15.0-dev.2
version = 5.18.1-dev.2

View File

@@ -776,8 +776,8 @@ public final class app/revanced/patches/shared/misc/settings/preference/TextPref
}
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 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 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;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 {
@@ -816,6 +816,14 @@ public final class app/revanced/patches/spotify/lite/ondemand/OnDemandPatchKt {
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 static final fun getSpoofSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
@@ -1088,6 +1096,14 @@ public final class app/revanced/patches/youtube/interaction/seekbar/EnableSlideT
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 static final fun getSeekbarThumbnailsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
@@ -1177,17 +1193,7 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
}
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 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 {
@@ -1382,6 +1388,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_47_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 {

View File

@@ -14,7 +14,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
val hideSponsoredStoriesPatch = bytecodePatch(
name = "Hide 'Sponsored Stories'",
) {
compatibleWith("com.facebook.katana")
compatibleWith("com.facebook.katana"("490.0.0.63.82"))
execute {
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod

View File

@@ -145,7 +145,25 @@ internal val patchIncludedExtensionMethodFingerprint = fingerprint {
internal const val MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG = 45645570L
internal val mediaFetchHotConfigFingerprint = fingerprint {
literal {
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG
}
literal { 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 }
}

View File

@@ -10,6 +10,7 @@ import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -31,7 +32,9 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
fun spoofVideoStreamsPatch(
block: BytecodePatchBuilder.() -> Unit = {},
applyMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
fixMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
fixMediaFetchHotConfigAlternativeChanges: BytecodePatchBuilder.() -> Boolean = { false },
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
executeBlock: BytecodePatchContext.() -> Unit = {},
) = bytecodePatch(
name = "Spoof video streams",
@@ -92,14 +95,14 @@ fun spoofVideoStreamsPatch(
getReference<MethodReference>()?.name == "newUrlRequestBuilder"
}
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
val freeRegister = getInstruction<OneRegisterInstruction>(newRequestBuilderIndex + 1).registerA
val freeRegister = findFreeRegister(newRequestBuilderIndex, urlRegister)
addInstructions(
newRequestBuilderIndex,
"""
move-object v$freeRegister, p1
invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V
""",
move-object v$freeRegister, p1
invoke-static { v$urlRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V
"""
)
}
@@ -241,13 +244,27 @@ fun spoofVideoStreamsPatch(
// region turn off stream config replacement feature flag.
if (applyMediaFetchHotConfigChanges()) {
if (fixMediaFetchHotConfigChanges()) {
mediaFetchHotConfigFingerprint.method.insertFeatureFlagBooleanOverride(
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
if (fixMediaFetchHotConfigAlternativeChanges()) {
mediaFetchHotConfigAlternativeFingerprint.method.insertFeatureFlagBooleanOverride(
MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
if (fixParsePlaybackResponseFeatureFlag()) {
playbackStartDescriptorFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride(
PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z"
)
}
// endregion
executeBlock()

View File

@@ -10,6 +10,7 @@ import org.w3c.dom.Element
val customThemePatch = resourcePatch(
name = "Custom theme",
description = "Applies a custom theme.",
use = false,
) {
compatibleWith("com.spotify.music")

View File

@@ -0,0 +1,23 @@
package app.revanced.patches.spotify.misc
import app.revanced.patcher.fingerprint
internal val accountAttributeFingerprint = fingerprint {
custom { _, c -> c.endsWith("internal/AccountAttribute;") }
}
internal val productStateProtoFingerprint = fingerprint {
returns("Ljava/util/Map;")
custom { _, classDef ->
classDef.endsWith("ProductStateProto;")
}
}
internal val buildQueryParametersFingerprint = fingerprint {
strings("trackRows", "device_type:tablet")
}
internal val contextMenuExperimentsFingerprint = fingerprint {
parameters("L")
strings("remove_ads_upsell_enabled")
}

View File

@@ -0,0 +1,5 @@
package app.revanced.patches.spotify.misc.extension
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
val sharedExtensionPatch = sharedExtensionPatch("spotify", spotifyMainActivityOnCreate)

View File

@@ -0,0 +1,10 @@
package app.revanced.patches.spotify.misc.extension
import app.revanced.patches.shared.misc.extension.extensionHook
internal val spotifyMainActivityOnCreate = extensionHook {
custom { method, classDef ->
classDef.type == "Lcom/spotify/music/SpotifyMainActivity;" &&
method.name == "onCreate"
}
}

View File

@@ -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 }
}

View File

@@ -1,50 +1,12 @@
package app.revanced.patches.spotify.navbar
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
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",
]
}
}
import app.revanced.patches.spotify.misc.unlockPremiumPatch
@Deprecated("Superseded by unlockPremiumPatch", ReplaceWith("unlockPremiumPatch"))
@Suppress("unused")
val premiumNavbarTabPatch = bytecodePatch(
name = "Premium navbar tab",
description = "Hides the premium tab from the navigation bar.",
) {
dependsOn(premiumNavbarTabResourcePatch)
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
""",
)
}
dependsOn(unlockPremiumPatch)
}

View File

@@ -10,7 +10,13 @@ val dynamicColorPatch = resourcePatch(
name = "Dynamic color",
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 {
val resDirectory = get("res")

View File

@@ -11,7 +11,15 @@ fun hookPatch(
) = bytecodePatch(name) {
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 {
addJsonHook(JsonHook(hookClassDescriptor))

View File

@@ -37,7 +37,13 @@ val changeLinkSharingDomainPatch = bytecodePatch(
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(
key = "domainName",

View File

@@ -8,7 +8,13 @@ val sanitizeSharingLinksPatch = bytecodePatch(
name = "Sanitize sharing links",
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 {
sanitizeSharingLinksFingerprint.method.addInstructions(

View File

@@ -82,9 +82,8 @@ val hideAdsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -29,9 +29,8 @@ val hideGetPremiumPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -27,9 +27,8 @@ val videoAdsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -57,9 +57,8 @@ val copyVideoUrlPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -28,9 +28,8 @@ val removeViewerDiscretionDialogPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -72,9 +72,8 @@ val downloadsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -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.settingsPatch
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/DisablePreciseSeekingGesturePatch;"
val disablePreciseSeekingGesturePatch = bytecodePatch(
name = "Disable precise seeking gesture",
description = "Adds an option to disable precise seeking when swiping up on the seekbar.",
) {
dependsOn(
@@ -21,26 +23,12 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
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 {
addResources("youtube", "interaction.seekbar.disablePreciseSeekingGesturePatch")
PreferenceScreen.SEEKBAR.addPreferences(
SwitchPreference("revanced_disable_precise_seeking_gesture"),
)
val extensionMethodDescriptor =
"Lapp/revanced/extension/youtube/patches/DisablePreciseSeekingGesturePatch;"
allowSwipingUpGestureFingerprint.match(
swipingUpGestureParentFingerprint.originalClassDef,
@@ -48,7 +36,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
addInstructionsWithLabels(
0,
"""
invoke-static { }, $extensionMethodDescriptor->isGestureDisabled()Z
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->isGestureDisabled()Z
move-result v0
if-eqz v0, :disabled
return-void
@@ -63,7 +51,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
addInstructionsWithLabels(
0,
"""
invoke-static { }, $extensionMethodDescriptor->isGestureDisabled()Z
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->isGestureDisabled()Z
move-result v0
if-eqz v0, :disabled
const/4 v0, 0x0

View File

@@ -15,7 +15,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
val enableSeekbarTappingPatch = bytecodePatch(
name = "Enable tap to seek",
description = "Adds an option to enable tap to seek on the seekbar of the video player.",
) {
dependsOn(
@@ -24,18 +23,6 @@ val enableSeekbarTappingPatch = bytecodePatch(
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 {
addResources("youtube", "interaction.seekbar.enableSeekbarTappingPatch")

View File

@@ -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.reference.MethodReference
internal const val EXTENSION_METHOD_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/SlideToSeekPatch;->isSlideToSeekDisabled(Z)Z"
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/SlideToSeekPatch;"
val enableSlideToSeekPatch = bytecodePatch(
name = "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."
) {
@@ -33,18 +31,6 @@ val enableSlideToSeekPatch = bytecodePatch(
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 {
addResources("youtube", "interaction.seekbar.enableSlideToSeekPatch")
@@ -60,6 +46,8 @@ val enableSlideToSeekPatch = bytecodePatch(
val checkReference = slideToSeekFingerprint.method.getInstruction(checkIndex)
.getReference<MethodReference>()!!
val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->isSlideToSeekDisabled(Z)Z"
// A/B check method was only called on this class.
slideToSeekFingerprint.classDef.methods.forEach { method ->
method.findInstructionIndicesReversed {
@@ -71,7 +59,7 @@ val enableSlideToSeekPatch = bytecodePatch(
addInstructions(
index + 2,
"""
invoke-static { v$register }, $EXTENSION_METHOD_DESCRIPTOR
invoke-static { v$register }, $extensionMethodDescriptor
move-result v$register
""",
)
@@ -96,7 +84,7 @@ val enableSlideToSeekPatch = bytecodePatch(
addInstructions(
targetIndex + 1,
"""
invoke-static { v$targetRegister }, $EXTENSION_METHOD_DESCRIPTOR
invoke-static { v$targetRegister }, $extensionMethodDescriptor
move-result v$targetRegister
""",
)
@@ -110,7 +98,7 @@ val enableSlideToSeekPatch = bytecodePatch(
addInstructions(
insertIndex,
"""
invoke-static { v$targetRegister }, $EXTENSION_METHOD_DESCRIPTOR
invoke-static { v$targetRegister }, $extensionMethodDescriptor
move-result v$targetRegister
""",
)

View File

@@ -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
""",
)
}
}

View File

@@ -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",
)
)
}

View File

@@ -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.misc.extension.sharedExtensionPatch
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.settings.PreferenceScreen
@@ -17,7 +18,6 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;"
val seekbarThumbnailsPatch = bytecodePatch(
name = "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.",
) {
@@ -27,19 +27,13 @@ val seekbarThumbnailsPatch = bytecodePatch(
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 {
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")
if (is_19_17_or_greater) {

View File

@@ -84,9 +84,8 @@ val swipeControlsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -26,9 +26,8 @@ val autoCaptionsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -47,9 +47,8 @@ val customBrandingPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -45,9 +45,8 @@ val changeHeaderPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@@ -26,9 +26,8 @@ val hideButtonsPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -44,9 +44,8 @@ val navigationButtonsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -58,9 +58,8 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -37,9 +37,8 @@ val changeFormFactorPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -63,9 +63,8 @@ val hideEndscreenCardsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -35,9 +35,8 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -33,9 +33,8 @@ val disableFullscreenAmbientModePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -15,7 +15,21 @@ internal val hideShowMoreButtonFingerprint = fingerprint {
literal { expandButtonDownId }
}
/**
* 20.07+
*/
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")
opcodes(
Opcode.IGET_OBJECT,
@@ -110,7 +124,6 @@ internal val showFloatingMicrophoneButtonFingerprint = fingerprint {
opcodes(
Opcode.IGET_BOOLEAN,
Opcode.IF_EQZ,
Opcode.RETURN_VOID,
)
literal { fabButtonId }
}

View File

@@ -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.lithoFilterPatch
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.versionCheckPatch
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.findInstructionIndicesReversedOrThrow
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.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@@ -120,7 +122,6 @@ val hideLayoutComponentsPatch = bytecodePatch(
addResourcesPatch,
hideLayoutComponentsResourcePatch,
navigationBarHookPatch,
versionCheckPatch
)
compatibleWith(
@@ -132,6 +133,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -142,6 +144,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
PreferenceScreenPreference(
key = "revanced_hide_description_components_screen",
preferences = setOf(
SwitchPreference("revanced_hide_ai_generated_video_summary_section"),
SwitchPreference("revanced_hide_attributes_section"),
SwitchPreference("revanced_hide_chapters_section"),
SwitchPreference("revanced_hide_info_cards_section"),
@@ -154,7 +157,8 @@ val hideLayoutComponentsPatch = bytecodePatch(
PreferenceScreenPreference(
"revanced_comments_screen",
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_section"),
SwitchPreference("revanced_hide_comments_create_a_short_button"),
@@ -245,29 +249,31 @@ val hideLayoutComponentsPatch = bytecodePatch(
// region Mix playlists
parseElementFromBufferFingerprint.method.apply {
val startIndex = parseElementFromBufferFingerprint.patternMatch!!.startIndex
// Target code is a mess with a lot of register moves.
// There is no simple way to find a free register for all versions so this is hard coded.
val freeRegister = if (is_19_47_or_greater) 6 else 0
val byteArrayParameter = "p3"
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC }
val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC
(if (is_20_07_or_greater) parseElementFromBufferFingerprint
else parseElementFromBufferLegacyFingerprint).let {
it.method.apply {
val byteArrayParameter = "p3"
val startIndex = it.patternMatch!!.startIndex
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC }
val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC
val insertIndex = startIndex + 1
val freeRegister = findFreeRegister(insertIndex, conversionContextRegister, returnEmptyComponentRegister)
addInstructionsWithLabels(
startIndex + 1,
"""
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
goto :return_empty_component
:show
const/4 v$freeRegister, 0x0 # Restore register, required for 19.16
""",
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
)
addInstructionsWithLabels(
insertIndex,
"""
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
goto :return_empty_component
:show
nop
""",
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
)
}
}
// endregion
@@ -343,19 +349,18 @@ val hideLayoutComponentsPatch = bytecodePatch(
// region hide floating microphone
showFloatingMicrophoneButtonFingerprint.let {
it.method.apply {
val startIndex = it.patternMatch!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(startIndex).registerA
showFloatingMicrophoneButtonFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(fabButtonId)
val booleanIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.IGET_BOOLEAN)
val register = getInstruction<TwoRegisterInstruction>(booleanIndex).registerA
addInstructions(
startIndex + 1,
"""
addInstructions(
booleanIndex + 1,
"""
invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideFloatingMicrophoneButton(Z)Z
move-result v$register
""",
)
}
"""
)
}
// endregion

View File

@@ -61,9 +61,8 @@ val hideInfoCardsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -28,9 +28,8 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -33,9 +33,8 @@ val disableRollingNumberAnimationPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -1,59 +1,11 @@
package app.revanced.patches.youtube.layout.hide.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
import app.revanced.patches.youtube.interaction.seekbar.hideSeekbarPatch
val hideSeekbarPatch = bytecodePatch(
name = "Hide seekbar",
description = "Adds an option to hide the seekbar.",
) {
@Deprecated("Patch was moved to app.revanced.patches.youtube.interaction.seekbar")
val hideSeekbarPatch = bytecodePatch {
dependsOn(
sharedExtensionPatch,
settingsPatch,
seekbarColorPatch,
addResourcesPatch,
hideSeekbarPatch
)
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 {
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
""",
)
}
}

View File

@@ -176,9 +176,8 @@ val hideShortsComponentsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -25,9 +25,8 @@ val hideTimestampPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -30,7 +30,7 @@ internal val miniplayerModernAddViewListenerFingerprint = fingerprint {
internal val miniplayerModernCloseButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerClose }
}
@@ -62,7 +62,7 @@ internal val miniplayerOnCloseHandlerFingerprint = fingerprint {
*/
internal val miniplayerModernExpandButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerExpand }
}
@@ -82,7 +82,7 @@ internal val miniplayerModernExpandCloseDrawablesFingerprint = fingerprint {
*/
internal val miniplayerModernForwardButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerForwardButton }
}
@@ -92,7 +92,6 @@ internal val miniplayerModernForwardButtonFingerprint = fingerprint {
*/
internal val miniplayerModernOverlayViewFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters()
literal { scrimOverlay }
}
@@ -102,7 +101,7 @@ internal val miniplayerModernOverlayViewFingerprint = fingerprint {
*/
internal val miniplayerModernRewindButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerRewindButton }
}
@@ -114,6 +113,13 @@ internal val miniplayerModernViewParentFingerprint = fingerprint {
strings("player_overlay_modern_mini_player_controls")
}
internal val miniplayerModernActionButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters()
literal { modernMiniPlayerOverlayActionButton }
}
internal val miniplayerMinimumSizeFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
custom { method, _ ->

View File

@@ -34,27 +34,29 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
var floatyBarButtonTopMargin = -1L
internal var floatyBarButtonTopMargin = -1L
private set
// Only available in 19.15 and upwards.
var ytOutlineXWhite24 = -1L
internal var ytOutlineXWhite24 = -1L
private set
var ytOutlinePictureInPictureWhite24 = -1L
internal var ytOutlinePictureInPictureWhite24 = -1L
private set
var scrimOverlay = -1L
internal var scrimOverlay = -1L
private set
var modernMiniplayerClose = -1L
internal var modernMiniplayerClose = -1L
private set
var modernMiniplayerExpand = -1L
internal var modernMiniplayerExpand = -1L
private set
var modernMiniplayerRewindButton = -1L
internal var modernMiniplayerRewindButton = -1L
private set
var modernMiniplayerForwardButton = -1L
internal var modernMiniplayerForwardButton = -1L
private set
var playerOverlays = -1L
internal var modernMiniPlayerOverlayActionButton = -1L
private set
var miniplayerMaxSize = -1L
internal var playerOverlays = -1L
private set
internal var miniplayerMaxSize = -1L
private set
private val miniplayerResourcePatch = resourcePatch {
@@ -100,6 +102,11 @@ private val miniplayerResourcePatch = resourcePatch {
"modern_miniplayer_forward_button",
]
modernMiniPlayerOverlayActionButton = resourceMappings[
"id",
"modern_miniplayer_overlay_action_button"
]
// Resource id is not used during patching, but is used by extension.
// Verify the resource is present while patching.
resourceMappings[
@@ -167,6 +174,7 @@ val miniplayerPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -175,19 +183,25 @@ val miniplayerPatch = bytecodePatch(
val preferences = mutableSetOf<BasePreference>()
preferences +=
if (is_19_43_or_greater) {
if (is_20_03_or_greater) {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
)
} else if (is_19_43_or_greater) {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
entriesKey = "revanced_miniplayer_type_legacy_19_43_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_19_43_entry_values",
)
} else {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
entriesKey = "revanced_miniplayer_type_legacy_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_entry_values",
entriesKey = "revanced_miniplayer_type_legacy_19_16_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_19_16_entry_values",
)
}
@@ -209,13 +223,13 @@ val miniplayerPatch = bytecodePatch(
preferences += SwitchPreference("revanced_miniplayer_hide_subtext")
preferences += if (is_19_26_or_greater) {
SwitchPreference("revanced_miniplayer_hide_expand_close")
SwitchPreference("revanced_miniplayer_hide_overlay_buttons")
} else {
SwitchPreference(
key = "revanced_miniplayer_hide_expand_close",
titleKey = "revanced_miniplayer_hide_expand_close_legacy_title",
summaryOnKey = "revanced_miniplayer_hide_expand_close_legacy_summary_on",
summaryOffKey = "revanced_miniplayer_hide_expand_close_legacy_summary_off",
key = "revanced_miniplayer_hide_overlay_buttons",
titleKey = "revanced_miniplayer_hide_overlay_buttons_legacy_title",
summaryOnKey = "revanced_miniplayer_hide_overlay_buttons_legacy_summary_on",
summaryOffKey = "revanced_miniplayer_hide_overlay_buttons_legacy_summary_off",
)
}
@@ -365,7 +379,7 @@ val miniplayerPatch = bytecodePatch(
if (is_19_23_or_greater) {
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
"enableMiniplayerDragAndDrop",
"getMiniplayerDragAndDrop",
)
}
@@ -382,7 +396,7 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
"enableMiniplayerDoubleTapAction",
"getMiniplayerDoubleTapAction",
)
}
@@ -398,7 +412,7 @@ val miniplayerPatch = bytecodePatch(
addInstructions(
targetIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setMiniplayerDefaultSize(I)I
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDefaultSize(I)I
move-result v$register
""",
)
@@ -421,7 +435,7 @@ val miniplayerPatch = bytecodePatch(
if (is_19_36_or_greater) {
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
"setRoundedCorners",
"getRoundedCorners",
)
}
@@ -433,7 +447,7 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"setHorizontalDrag",
"getHorizontalDrag",
)
}
@@ -473,6 +487,11 @@ val miniplayerPatch = bytecodePatch(
modernMiniplayerClose,
"hideMiniplayerExpandClose",
),
Triple(
miniplayerModernActionButtonFingerprint,
modernMiniPlayerOverlayActionButton,
"hideMiniplayerActionButton"
),
Triple(
miniplayerModernRewindButtonFingerprint,
modernMiniplayerRewindButton,
@@ -490,12 +509,25 @@ val miniplayerPatch = bytecodePatch(
),
).forEach { (fingerprint, literalValue, methodName) ->
fingerprint.match(
miniplayerModernViewParentFingerprint.classDef,
).method.hookInflatedView(
literalValue,
"Landroid/widget/ImageView;",
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V",
)
miniplayerModernViewParentFingerprint.originalClassDef
).method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literalValue)
val checkCastIndex = indexOfFirstInstruction(literalIndex) {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == "Landroid/widget/ImageView;"
}
val viewIndex = if (checkCastIndex >= 0) {
checkCastIndex
} else {
indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT)
}
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
addInstruction(
viewIndex + 1,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V"
)
}
}
miniplayerModernAddViewListenerFingerprint.match(
@@ -510,33 +542,40 @@ val miniplayerPatch = bytecodePatch(
// Modern 2 uses the same overlay controls as the regular video player,
// and the overlay views are added at runtime.
// Add a hook to the overlay class, and pass the added views to extension.
// Problem is fixed in 19.21+
//
// NOTE: Modern 2 uses the same video UI as the regular player except resized to smaller.
// This patch code could be used to hide other player overlays that do not use Litho.
playerOverlaysLayoutFingerprint.classDef.methods.add(
ImmutableMethod(
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
"addView",
listOf(
ImmutableMethodParameter("Landroid/view/View;", null, null),
ImmutableMethodParameter("I", null, null),
ImmutableMethodParameter("Landroid/view/ViewGroup\$LayoutParams;", null, null),
),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
"""
)
}
)
if (!is_19_17_or_greater) {
playerOverlaysLayoutFingerprint.classDef.methods.add(
ImmutableMethod(
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
"addView",
listOf(
ImmutableMethodParameter("Landroid/view/View;", null, null),
ImmutableMethodParameter("I", null, null),
ImmutableMethodParameter(
"Landroid/view/ViewGroup\$LayoutParams;",
null,
null
),
),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
"""
)
}
)
}
// endregion
}

View File

@@ -25,9 +25,8 @@ val playerPopupPanelsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -16,9 +16,8 @@ val playerControlsBackgroundPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -25,9 +25,8 @@ internal val exitFullscreenPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@@ -27,6 +27,7 @@ val openVideosFullscreenPatch = bytecodePatch(
"com.google.android.youtube"(
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@@ -56,9 +56,8 @@ val customPlayerOverlayOpacityPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -12,6 +12,7 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_33_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.addSettingPreference
import app.revanced.patches.youtube.misc.settings.newIntent
@@ -56,9 +57,8 @@ val returnYouTubeDislikePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -121,7 +121,7 @@ val returnYouTubeDislikePatch = bytecodePatch(
val tempRegister: Int
val charSequenceRegister: Int
if (is_19_33_or_greater) {
if (is_19_33_or_greater && !is_20_10_or_greater) {
insertIndex = indexOfFirstInstructionOrThrow {
(opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE)
&& getReference<MethodReference>()?.returnType == textDataClassType
@@ -179,9 +179,6 @@ val returnYouTubeDislikePatch = bytecodePatch(
// region Hook rolling numbers.
// Do this last to allow patching old unsupported versions (if the user really wants),
// On older unsupported version this will fail to match and throw an exception,
// but everything will still work correctly anyway.
val dislikesIndex = rollingNumberSetterFingerprint.patternMatch!!.endIndex
rollingNumberSetterFingerprint.method.apply {

View File

@@ -18,7 +18,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/WideSearchbarPatch;"
val wideSearchbarPatch = bytecodePatch(
name = "Wide searchbar",
name = "Wide search bar",
description = "Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.",
) {
dependsOn(
@@ -33,9 +33,8 @@ val wideSearchbarPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -37,12 +37,25 @@ internal val shortsSeekbarColorFingerprint = fingerprint {
literal { reelTimeBarPlayedColorId }
}
internal val playerSeekbarHandleColorFingerprint = fingerprint {
internal val playerSeekbarHandle1ColorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("Landroid/content/Context;")
literal { ytStaticBrandRedId }
custom { method, _ ->
method.containsLiteralInstruction(ytTextSecondaryId) &&
method.containsLiteralInstruction(ytStaticBrandRedId)
}
}
internal val playerSeekbarHandle2ColorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("Landroid/content/Context;")
custom { method, _ ->
method.containsLiteralInstruction(inlineTimeBarLiveSeekableRangeId) &&
method.containsLiteralInstruction(ytStaticBrandRedId)
}
}
internal val watchHistoryMenuUseProgressDrawableFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")

View File

@@ -53,6 +53,10 @@ internal var ytYoutubeMagentaColorId = -1L
private set
internal var ytStaticBrandRedId = -1L
private set
internal var ytTextSecondaryId = -1L
private set
internal var inlineTimeBarLiveSeekableRangeId = -1L
private set
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
@@ -76,6 +80,18 @@ private val seekbarColorResourcePatch = resourcePatch {
"color",
"inline_time_bar_played_not_highlighted_color",
]
ytStaticBrandRedId = resourceMappings[
"attr",
"ytStaticBrandRed"
]
ytTextSecondaryId = resourceMappings[
"attr",
"ytTextSecondary"
]
inlineTimeBarLiveSeekableRangeId = resourceMappings[
"color",
"inline_time_bar_live_seekable_range"
]
// Modify the resume playback drawable and replace the progress bar with a custom drawable.
document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
@@ -211,7 +227,7 @@ val seekbarColorPatch = bytecodePatch(
)
execute {
fun MutableMethod.addColorChangeInstructions(resourceId: Long, methodName: String) {
fun MutableMethod.addColorChangeInstructions(resourceId: Long) {
val index = indexOfFirstLiteralInstructionOrThrow(resourceId)
val insertIndex = indexOfFirstInstructionOrThrow(index, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
@@ -219,19 +235,19 @@ val seekbarColorPatch = bytecodePatch(
addInstructions(
insertIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(I)I
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I
move-result v$register
"""
)
}
playerSeekbarColorFingerprint.method.apply {
addColorChangeInstructions(inlineTimeBarColorizedBarPlayedColorDarkId, "getVideoPlayerSeekbarColor")
addColorChangeInstructions(inlineTimeBarPlayedNotHighlightedColorId, "getVideoPlayerSeekbarColor")
addColorChangeInstructions(inlineTimeBarColorizedBarPlayedColorDarkId)
addColorChangeInstructions(inlineTimeBarPlayedNotHighlightedColorId)
}
shortsSeekbarColorFingerprint.method.apply {
addColorChangeInstructions(reelTimeBarPlayedColorId, "getVideoPlayerSeekbarColor")
addColorChangeInstructions(reelTimeBarPlayedColorId)
}
setSeekbarClickedColorFingerprint.originalMethod.let {
@@ -257,8 +273,11 @@ val seekbarColorPatch = bytecodePatch(
// 19.25+ changes
playerSeekbarHandleColorFingerprint.method.apply {
addColorChangeInstructions(ytStaticBrandRedId, "getVideoPlayerSeekbarColor")
arrayOf(
playerSeekbarHandle1ColorFingerprint,
playerSeekbarHandle2ColorFingerprint
).forEach {
it.method.addColorChangeInstructions(ytStaticBrandRedId)
}
// If hiding feed seekbar thumbnails, then turn off the cairo gradient

View File

@@ -37,9 +37,8 @@ val shortsAutoplayPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -16,9 +16,9 @@ import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -45,9 +45,8 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -107,11 +106,12 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
getReference<MethodReference>()?.returnType ==
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"
}
val freeRegister = getInstruction<FiveRegisterInstruction>(index).registerC
val playbackStartRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA
val insertIndex = index + 2
val freeRegister = findFreeRegister(insertIndex, playbackStartRegister)
addInstructionsWithLabels(
index + 2,
insertIndex,
extensionInstructions(playbackStartRegister, freeRegister)
)
}

View File

@@ -110,9 +110,8 @@ val sponsorBlockPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -16,6 +16,7 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_43_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.settingsPatch
@@ -57,13 +58,12 @@ val spoofAppVersionPatch = bytecodePatch(
compatibleWith(
"com.google.android.youtube"(
// "19.16.39", // Cannot be supported because the lowest spoof target is higher.
// "19.25.37", // Cannot be supported because the lowest spoof target is higher.
// "19.34.42", // Cannot be supported because the lowest spoof target is higher.
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -79,19 +79,27 @@ val spoofAppVersionPatch = bytecodePatch(
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = setOf(
SwitchPreference("revanced_spoof_app_version"),
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
)
if (is_19_43_or_greater) {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
)
} else {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
entriesKey = "revanced_spoof_app_version_target_legacy_entries",
entryValuesKey = "revanced_spoof_app_version_target_legacy_entry_values"
)
}
)
)
)
/**
* If a user really wants to spoof to very old versions with the latest app target
* they can modify the import/export spoof version. But when spoofing the 19.20.xx
* or earlier the Library tab can crash due to missing image resources trying to load.
* As a temporary workaround, do not set an image in the toolbar when the enum name is UNKNOWN.
* If spoofing to target 19.20 or earlier the Library tab can crash due to
* missing image resources. As a workaround, do not set an image in the
* toolbar when the enum name is UNKNOWN.
*/
toolBarButtonFingerprint.method.apply {
val getDrawableIndex = indexOfGetDrawableInstruction(this)

View File

@@ -33,9 +33,8 @@ val changeStartPagePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -7,11 +7,14 @@ 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.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_20_02_or_greater
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -38,6 +41,7 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -48,25 +52,47 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
SwitchPreference("revanced_disable_resuming_shorts_player"),
)
userWasInShortsFingerprint.method.apply {
val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
getReference<MethodReference>()?.name == "isDone"
}
val freeRegister = getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA
if (is_20_02_or_greater) {
userWasInShortsAlternativeFingerprint.let {
it.method.apply {
val stringIndex = it.stringMatches!!.first().index
val booleanValueIndex = indexOfFirstInstructionReversedOrThrow(stringIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "booleanValue"
}
val booleanValueRegister =
getInstruction<OneRegisterInstruction>(booleanValueIndex + 1).registerA
addInstructionsAtControlFlowLabel(
listenableInstructionIndex,
"""
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z
move-result v$freeRegister
if-eqz v$freeRegister, :show_startup_shorts_player
return-void
:show_startup_shorts_player
nop
""",
)
addInstructions(
booleanValueIndex + 2, """
invoke-static {v$booleanValueRegister}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer(Z)Z
move-result v$booleanValueRegister
"""
)
}
}
} else {
userWasInShortsLegacyFingerprint.method.apply {
val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_INTERFACE &&
reference?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
reference.name == "isDone"
}
val freeRegister = findFreeRegister(listenableInstructionIndex)
addInstructionsAtControlFlowLabel(
listenableInstructionIndex,
"""
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
return-void
:show
nop
"""
)
}
}
userWasInShortsConfigFingerprint.method.addInstructions(

View File

@@ -4,7 +4,17 @@ import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
internal val userWasInShortsFingerprint = fingerprint {
/**
* YouTube 20.02.08 ~
*/
internal val userWasInShortsAlternativeFingerprint = fingerprint {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Ljava/lang/Object;")
strings("userIsInShorts: ")
}
internal val userWasInShortsLegacyFingerprint = fingerprint {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Ljava/lang/Object;")

View File

@@ -221,9 +221,8 @@ val themePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -37,9 +37,8 @@ val alternativeThumbnailsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -31,9 +31,8 @@ val bypassImageRegionRestrictionsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -27,9 +27,8 @@ val announcementsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -28,9 +28,8 @@ val autoRepeatPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -52,9 +52,8 @@ val backgroundPlaybackPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -38,9 +38,8 @@ val enableDebuggingPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -28,9 +28,8 @@ val spoofDeviceDimensionsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -25,9 +25,8 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -8,6 +8,7 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@@ -42,13 +43,14 @@ val fixPlaybackSpeedWhilePlayingPatch = bytecodePatch{
}
playbackSpeedInFeedsFingerprint.method.apply {
val freeRegister = implementation!!.registerCount - parameters.size - 2
val playbackSpeedIndex = indexOfGetPlaybackSpeedInstruction(this)
val playbackSpeedRegister = getInstruction<TwoRegisterInstruction>(playbackSpeedIndex).registerA
val returnIndex = indexOfFirstInstructionOrThrow(playbackSpeedIndex, Opcode.RETURN_VOID)
val insertIndex = playbackSpeedIndex + 1
val freeRegister = findFreeRegister(insertIndex, playbackSpeedRegister)
addInstructionsWithLabels(
playbackSpeedIndex + 1,
insertIndex,
"""
invoke-static { v$playbackSpeedRegister }, $EXTENSION_CLASS_DESCRIPTOR->playbackSpeedChanged(F)Z
move-result v$freeRegister

View File

@@ -39,9 +39,8 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
}

View File

@@ -13,9 +13,11 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
val bypassURLRedirectsPatch = bytecodePatch(
name = "Bypass URL redirects",
@@ -37,6 +39,7 @@ val bypassURLRedirectsPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@@ -80,3 +83,8 @@ internal fun Method.findUriParseIndex() = indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.returnType == "Landroid/net/Uri;" && reference.name == "parse"
}
internal fun Method.findWebViewCheckCastIndex() = indexOfFirstInstruction {
val reference = getReference<TypeReference>()
opcode == Opcode.CHECK_CAST && reference?.type?.endsWith("/WebviewEndpointOuterClass${'$'}WebviewEndpoint;") == true
}

View File

@@ -11,12 +11,21 @@ internal val abUriParserFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Ljava/lang/Object")
parameters("Ljava/lang/Object")
strings(
"Found entityKey=`",
"` that does not contain a PlaylistVideoEntityId message as it's identifier.",
)
custom { method, _ ->
method.findUriParseIndex() >= 0
method.findUriParseIndex() >= 0 && method.findWebViewCheckCastIndex() >= 0
}
}
/**
* Target 19.33+
*/
internal val httpUriParserFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Landroid/net/Uri")
parameters("Ljava/lang/String")
strings("https", "://", "https:")
custom { methodDef, _ ->
methodDef.findUriParseIndex() >= 0
}
}
@@ -47,19 +56,6 @@ internal val abUriParserLegacyFingerprint = fingerprint {
}
}
/**
* Target 19.33+
*/
internal val httpUriParserFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Landroid/net/Uri")
parameters("Ljava/lang/String")
strings("https", "https:", "://")
custom { methodDef, _ ->
methodDef.findUriParseIndex() >= 0
}
}
internal val httpUriParserLegacyFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Landroid/net/Uri")

View File

@@ -45,9 +45,8 @@ val openLinksExternallyPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@@ -10,7 +10,11 @@ import com.android.tools.smali.dexlib2.Opcode
* In 19.18+ this resolves to a different method.
*/
internal val componentContextParserFingerprint = fingerprint {
strings("Component was not found %s because it was removed due to duplicate converter bindings.")
strings(
"TreeNode result must be set.",
// String is a partial match and changed slightly in 20.03+
"it was removed due to duplicate converter bindings."
)
}
internal val lithoFilterFingerprint = fingerprint {

View File

@@ -8,19 +8,21 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_18_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_05_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.*
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -190,17 +192,7 @@ val lithoFilterPatch = bytecodePatch(
},
).registerA
// Find a free temporary register.
val freeRegister = getInstruction<OneRegisterInstruction>(
// Immediately before is a StringBuilder append constant character.
indexOfFirstInstructionReversedOrThrow(insertHookIndex, Opcode.CONST_16),
).registerA
// Verify the temp register will not clobber the method result register.
if (stringBuilderRegister == freeRegister) {
throw PatchException("Free register will clobber StringBuilder register")
}
val freeRegister = findFreeRegister(insertHookIndex, identifierRegister, stringBuilderRegister)
val invokeFilterInstructions = """
invoke-static { v$identifierRegister, v$stringBuilderRegister }, $EXTENSION_CLASS_DESCRIPTOR->filter(Ljava/lang/String;Ljava/lang/StringBuilder;)Z
move-result v$freeRegister
@@ -235,7 +227,10 @@ val lithoFilterPatch = bytecodePatch(
// Turn off native code that handles litho component names. If this feature is on then nearly
// all litho components have a null name and identifier/path filtering is completely broken.
if (is_19_25_or_greater) {
//
// Flag was removed in 20.05. It appears a new flag might be used instead (45660109L),
// but if the flag is forced on then litho filtering still works correctly.
if (is_19_25_or_greater && !is_20_05_or_greater) {
lithoComponentNameUpbFeatureFlagFingerprint.method.apply {
// Don't use return early, so the debug patch logs if this was originally on.
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN)

View File

@@ -46,6 +46,18 @@ var is_19_47_or_greater = false
private set
var is_19_49_or_greater = false
private set
var is_20_02_or_greater = false
private set
var is_20_03_or_greater = false
private set
var is_20_05_or_greater = false
private set
var is_20_07_or_greater = false
private set
var is_20_09_or_greater = false
private set
var is_20_10_or_greater = false
private set
val versionCheckPatch = resourcePatch(
description = "Uses the Play Store service version to find the major/minor version of the YouTube target app.",
@@ -80,5 +92,11 @@ val versionCheckPatch = resourcePatch(
is_19_46_or_greater = 244705000 <= playStoreServicesVersion
is_19_47_or_greater = 244799000 <= playStoreServicesVersion
is_19_49_or_greater = 245005000 <= playStoreServicesVersion
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
is_20_07_or_greater = 250805000 <= playStoreServicesVersion
is_20_09_or_greater = 251006000 <= playStoreServicesVersion
is_20_10_or_greater = 251105000 <= playStoreServicesVersion
}
}

Some files were not shown because too many files have changed in this diff Show More