Compare commits

...

73 Commits

Author SHA1 Message Date
semantic-release-bot
566875ea53 chore: Release v5.43.0-dev.2 [skip ci]
# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14)

### Bug Fixes

* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](10ea250d4a))
2025-10-14 05:58:15 +00:00
LisoUseInAIKyrios
10ea250d4a fix(YouTube - Custom branding): Use ReVanced icon for status bar notification icon (#6108) 2025-10-14 09:54:14 +04:00
github-actions[bot]
5bd0f11630 chore: Sync translations (#6117) 2025-10-14 09:53:13 +04:00
semantic-release-bot
4547ecb73c chore: Release v5.43.0-dev.1 [skip ci]
# [5.43.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.3...v5.43.0-dev.1) (2025-10-11)

### Features

* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](50f0b9c5ee))
2025-10-11 11:22:05 +00:00
Swakshan
50f0b9c5ee feat(Instagram): Add Hide suggested content patch (#6075) 2025-10-11 15:17:24 +04:00
semantic-release-bot
a8c4bdb8a6 chore: Release v5.42.2-dev.3 [skip ci]
## [5.42.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.2...v5.42.2-dev.3) (2025-10-11)

### Bug Fixes

* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](6555f6e6f8))
2025-10-11 08:04:05 +00:00
LisoUseInAIKyrios
6555f6e6f8 fix(YouTube - Custom branding): Do not add a broken custom icon if the user provides an invalid custom icon path 2025-10-11 12:00:26 +04:00
semantic-release-bot
a0e2c5c7b9 chore: Release v5.42.2-dev.2 [skip ci]
## [5.42.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.1...v5.42.2-dev.2) (2025-10-10)

### Bug Fixes

* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](54846253d7))
2025-10-10 22:05:28 +00:00
ADudeCalledLeo
54846253d7 fix(X / Twitter - Change Link Sharing Domain): Change link domain of share copy action (#6091)
Co-authored-by: nyraa <112930946+nyraa@users.noreply.github.com>
2025-10-11 02:01:44 +04:00
github-actions[bot]
a98e8f7370 chore: Sync translations (#6097) 2025-10-11 02:01:17 +04:00
semantic-release-bot
2d928e0cd6 chore: Release v5.42.2-dev.1 [skip ci]
## [5.42.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.42.2-dev.1) (2025-10-09)

### Bug Fixes

* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](be2b144cc9))
2025-10-09 08:03:53 +00:00
brosssh
be2b144cc9 fix(Instagram - Change sharing domain): Display patch option (#6089) 2025-10-09 10:00:17 +02:00
semantic-release-bot
52c0bb6aa2 chore: Release v5.42.1 [skip ci]
## [5.42.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1) (2025-10-08)

### Bug Fixes

* **YouTube - Custom Branding:** Resolve startup crash with root installation ([fd4b2e1](fd4b2e1bb9))
2025-10-08 07:47:41 +00:00
LisoUseInAIKyrios
38a49cc2a1 chore: Merge branch dev to main (#6080) 2025-10-08 11:44:39 +04:00
semantic-release-bot
91044b3a50 chore: Release v5.42.1-dev.1 [skip ci]
## [5.42.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1-dev.1) (2025-10-08)

### Bug Fixes

* **YouTube - Custom Branding:** Resolve startup crash with root installation ([fd4b2e1](fd4b2e1bb9))
2025-10-08 07:42:49 +00:00
LisoUseInAIKyrios
fd4b2e1bb9 fix(YouTube - Custom Branding): Resolve startup crash with root installation 2025-10-08 11:39:48 +04:00
semantic-release-bot
d0f20c8c7f chore: Release v5.42.0 [skip ci]
# [5.42.0](https://github.com/ReVanced/revanced-patches/compare/v5.41.0...v5.42.0) (2025-10-08)

### Bug Fixes

* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](9441e7acb4))
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](ae4b9474d3))
* **Instagram - Hide navigation buttons:** Resolve app startup crash ([080a226](080a226614))
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](19949e1695))
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](673609c2aa))
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](bd4ba2dae8))
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](9d6731660b))
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](76b0364c5b))
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](f03256c471))
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](7afeaebb5c))
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](a62ee43441))
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](328234f39a))
* **YouTube Music - Hide cast button:** Fix patching error ([28799a5](28799a548a))
* **YouTube Music - Hide cast button:** Resolve button not hiding ([7817885](7817885cff))
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](6b26346914))

### Features

* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](a50f3b5177))
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](20c413120b))
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](2154d89242))
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](08e8ead04f))
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](963a4ef43f))
* **Viber:** Add `Hide navigation buttons` patch ([#5991](https://github.com/ReVanced/revanced-patches/issues/5991)) ([5cb46c4](5cb46c4e91))
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](4c8b56f546))
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](d0d53d109e))
2025-10-08 06:16:06 +00:00
semantic-release-bot
d65dbc749c chore: Release v5.42.0 [skip ci]
# [5.42.0](https://github.com/ReVanced/revanced-patches/compare/v5.41.0...v5.42.0) (2025-10-08)

### Bug Fixes

* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](9441e7acb4))
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](ae4b9474d3))
* **Instagram - Hide navigation buttons:** Resolve app startup crash ([080a226](080a226614))
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](19949e1695))
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](673609c2aa))
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](bd4ba2dae8))
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](9d6731660b))
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](76b0364c5b))
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](f03256c471))
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](7afeaebb5c))
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](a62ee43441))
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](328234f39a))
* **YouTube Music - Hide cast button:** Fix patching error ([28799a5](28799a548a))
* **YouTube Music - Hide cast button:** Resolve button not hiding ([7817885](7817885cff))
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](6b26346914))

### Features

* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](a50f3b5177))
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](20c413120b))
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](2154d89242))
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](08e8ead04f))
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](963a4ef43f))
* **Viber:** Add `Hide navigation buttons` patch ([#5991](https://github.com/ReVanced/revanced-patches/issues/5991)) ([5cb46c4](5cb46c4e91))
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](4c8b56f546))
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](d0d53d109e))
2025-10-08 06:01:45 +00:00
LisoUseInAIKyrios
143dcef2b8 chore: Merge branch dev to main (#6015) 2025-10-08 09:57:48 +04:00
github-actions[bot]
dbfc5be464 chore: Sync translations (#6078) 2025-10-08 09:54:53 +04:00
LisoUseInAIKyrios
0fe545cad6 chore: Add links to the ReVanced brand guidelines 2025-10-08 09:47:27 +04:00
semantic-release-bot
feca17be68 chore: Release v5.42.0-dev.19 [skip ci]
# [5.42.0-dev.19](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.18...v5.42.0-dev.19) (2025-10-07)

### Bug Fixes

* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](7afeaebb5c))
2025-10-07 20:37:44 +00:00
LisoUseInAIKyrios
7afeaebb5c fix(YouTube - Spoof video streams): Do not allow VR AV1 if "Force AVC" is enabled 2025-10-08 00:34:45 +04:00
github-actions[bot]
60a581a632 chore: Sync translations (#6077) 2025-10-08 00:30:56 +04:00
LisoUseInAIKyrios
104d096ada chore: Change brand name to untranslatable 2025-10-07 23:53:51 +04:00
semantic-release-bot
19dcbd8efb chore: Release v5.42.0-dev.18 [skip ci]
# [5.42.0-dev.18](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.17...v5.42.0-dev.18) (2025-10-07)

### Features

* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](a50f3b5177))
2025-10-07 19:25:25 +00:00
MarcaD
a50f3b5177 feat(Custom branding): Add in-app settings to change icon and name (#6059)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-10-07 23:21:12 +04:00
semantic-release-bot
64d22a9c31 chore: Release v5.42.0-dev.17 [skip ci]
# [5.42.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.16...v5.42.0-dev.17) (2025-10-07)

### Bug Fixes

* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](bd4ba2dae8))
2025-10-07 15:46:50 +00:00
LisoUseInAIKyrios
bd4ba2dae8 fix(YouTube - Force original audio): Change patch to default on (#6070) 2025-10-07 19:41:32 +04:00
github-actions[bot]
f51b260d1d chore: Sync translations (#6073) 2025-10-07 19:40:18 +04:00
LisoUseInAIKyrios
63be54dd09 chore: Remove unneeded binary compatibility for code that was never released to main 2025-10-07 19:39:54 +04:00
semantic-release-bot
bb222d7a26 chore: Release v5.42.0-dev.16 [skip ci]
# [5.42.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.15...v5.42.0-dev.16) (2025-10-07)

### Bug Fixes

* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](f03256c471))
2025-10-07 15:19:06 +00:00
LisoUseInAIKyrios
f03256c471 fix(YouTube - Spoof video streams): Add "Allow Android VR AV1" setting (#6071) 2025-10-07 19:15:37 +04:00
semantic-release-bot
fe16433f20 chore: Release v5.42.0-dev.15 [skip ci]
# [5.42.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.14...v5.42.0-dev.15) (2025-10-07)

### Features

* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](2154d89242))
2025-10-07 12:42:11 +00:00
brosssh
2154d89242 feat(Instagram): Add Enable developer menu patch (#6043) 2025-10-07 16:37:20 +04:00
semantic-release-bot
277a8b6b47 chore: Release v5.42.0-dev.14 [skip ci]
# [5.42.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.13...v5.42.0-dev.14) (2025-10-07)

### Features

* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](20c413120b))
2025-10-07 11:45:19 +00:00
brosssh
20c413120b feat(Instagram): Add Custom share domain patch (#5998) 2025-10-07 15:40:37 +04:00
semantic-release-bot
5ed092bb7d chore: Release v5.42.0-dev.13 [skip ci]
# [5.42.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.12...v5.42.0-dev.13) (2025-10-07)

### Bug Fixes

* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](19949e1695))
2025-10-07 07:14:51 +00:00
Dawid Krajcarz
19949e1695 fix(Spotify): Change Hide Create button patch to default off (#6067) 2025-10-07 11:11:41 +04:00
github-actions[bot]
ec0acc0f13 chore: Sync translations (#6069) 2025-10-07 11:11:18 +04:00
LisoUseInAIKyrios
a30a849e6e refactor: Extract shared patch names/descriptions (#6056) 2025-10-07 01:15:03 +04:00
semantic-release-bot
603025a122 chore: Release v5.42.0-dev.12 [skip ci]
# [5.42.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.11...v5.42.0-dev.12) (2025-10-03)

### Bug Fixes

* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](9441e7acb4))

### Features

* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](963a4ef43f))
2025-10-03 07:25:03 +00:00
MarcaD
9441e7acb4 fix(Custom branding): Update ReVanced logo (#6049) 2025-10-03 11:19:27 +04:00
brosssh
963a4ef43f feat(Instagram): Add Sanitize sharing links patch (#5986)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-10-03 11:19:01 +04:00
semantic-release-bot
0acba30245 chore: Release v5.42.0-dev.11 [skip ci]
# [5.42.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.10...v5.42.0-dev.11) (2025-10-03)

### Bug Fixes

* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](6b26346914))
2025-10-03 06:57:20 +00:00
LisoUseInAIKyrios
6b26346914 fix(YouTube): Resolve UI components not hiding for some users (#6054) 2025-10-03 10:54:44 +04:00
github-actions[bot]
b1511c732d chore: Sync translations (#6055) 2025-10-03 10:53:07 +04:00
semantic-release-bot
26117e744c chore: Release v5.42.0-dev.10 [skip ci]
# [5.42.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.9...v5.42.0-dev.10) (2025-10-02)

### Bug Fixes

* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](a62ee43441))
2025-10-02 20:09:02 +00:00
LisoUseInAIKyrios
a62ee43441 fix(YouTube - Spoof video streams): Resolve playback dropping frames (#6051) 2025-10-03 00:05:23 +04:00
LisoUseInAIKyrios
6a799110d7 refactor(YouTube - Spoof video streams): Add 'supportsMultiAudioTracks' field 2025-10-01 22:37:10 +04:00
dependabot[bot]
aec17b93f7 chore(deps): Bump com.google.guava:guava from 33.4.0-jre to 33.5.0-jre (#6042) 2025-10-01 22:18:24 +04:00
dependabot[bot]
e7a1706be4 chore(deps): Bump actions/setup-node from 4 to 5 (#6038) 2025-10-01 22:16:40 +04:00
dependabot[bot]
9469604fe0 chore(deps-dev): Bump semantic-release from 24.2.7 to 24.2.9 (#6040) 2025-10-01 22:15:52 +04:00
semantic-release-bot
1a3a12df1a chore: Release v5.42.0-dev.9 [skip ci]
# [5.42.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.8...v5.42.0-dev.9) (2025-10-01)

### Bug Fixes

* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](ae4b9474d3))
2025-10-01 17:33:14 +00:00
MarcaD
ae4b9474d3 fix(Custom branding): Update ReVanced logo sizing (#6029) 2025-10-01 21:29:05 +04:00
github-actions[bot]
83ccd9d3f1 chore: Sync translations (#6037) 2025-10-01 19:04:51 +04:00
semantic-release-bot
526c7c05e2 chore: Release v5.42.0-dev.8 [skip ci]
# [5.42.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.7...v5.42.0-dev.8) (2025-10-01)

### Bug Fixes

* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](9d6731660b))

### Features

* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](d0d53d109e))
2025-10-01 15:04:39 +00:00
LisoUseInAIKyrios
d0d53d109e feat(YouTube Music): Add Force original audio patch (#6036) 2025-10-01 18:59:16 +04:00
LisoUseInAIKyrios
9d6731660b fix(YouTube - Force original language): Resolve some videos using Swedish audio track 2025-10-01 18:57:53 +04:00
semantic-release-bot
5a7e199162 chore: Release v5.42.0-dev.7 [skip ci]
# [5.42.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.6...v5.42.0-dev.7) (2025-10-01)

### Features

* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](08e8ead04f))
2025-10-01 06:25:01 +00:00
LisoUseInAIKyrios
0c662c8e3b chore(deps): Bump actions/checkout from 4 to 5 2025-10-01 10:19:09 +04:00
Swakshan
08e8ead04f feat(Instagram): Add Open links externally patch (#6012) 2025-10-01 10:17:19 +04:00
semantic-release-bot
d238a42708 chore: Release v5.42.0-dev.6 [skip ci]
# [5.42.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.5...v5.42.0-dev.6) (2025-09-30)

### Bug Fixes

* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](673609c2aa))
2025-09-30 20:09:49 +00:00
LisoUseInAIKyrios
673609c2aa fix(X / Twitter): Remove non functional and obsolete patch Open links with app chooser (#6033) 2025-10-01 00:06:40 +04:00
github-actions[bot]
5f1a485e8f chore: Sync translations (#6034) 2025-10-01 00:06:22 +04:00
LisoUseInAIKyrios
6961babee9 refactor(YouTube - Check watch history domain name resolution): Do not show redundant dialog cancel button 2025-09-30 12:11:06 +04:00
semantic-release-bot
328c9b6bbe chore: Release v5.42.0-dev.5 [skip ci]
# [5.42.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.4...v5.42.0-dev.5) (2025-09-28)

### Features

* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](4c8b56f546))
2025-09-28 11:30:51 +00:00
MarcaD
4c8b56f546 feat(YouTube Music): Add Custom branding patch (#6007)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-09-28 15:26:12 +04:00
semantic-release-bot
1754023dd6 chore: Release v5.42.0-dev.4 [skip ci]
# [5.42.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.3...v5.42.0-dev.4) (2025-09-28)

### Bug Fixes

* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](328234f39a))
2025-09-28 10:34:39 +00:00
LisoUseInAIKyrios
328234f39a fix(YouTube Music - GmsCore support): Handle sharing links to certain apps such as Instagram (#6026) 2025-09-28 14:31:40 +04:00
github-actions[bot]
326953cfc3 chore: Sync translations (#6028) 2025-09-28 14:30:01 +04:00
semantic-release-bot
725d5dc974 chore: Release v5.42.0-dev.3 [skip ci]
# [5.42.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.2...v5.42.0-dev.3) (2025-09-28)

### Bug Fixes

* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](76b0364c5b))
2025-09-28 10:25:37 +00:00
LisoUseInAIKyrios
76b0364c5b fix(YouTube - Hide end screen cards): Hide new type of end screen card (#6027) 2025-09-28 14:22:42 +04:00
264 changed files with 5588 additions and 2003 deletions

View File

@@ -12,10 +12,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '17' java-version: '17'

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Open pull request - name: Open pull request
uses: repo-sync/pull-request@v2 uses: repo-sync/pull-request@v2

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
ref: dev ref: dev
clean: true clean: true

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Preprocess strings - name: Preprocess strings
env: env:

View File

@@ -18,10 +18,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Setup Java - name: Setup Java
uses: actions/setup-java@v4 uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: '17' java-version: '17'
@@ -35,7 +35,7 @@ jobs:
run: ./gradlew :patches:buildAndroid clean run: ./gradlew :patches:buildAndroid clean
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: 'lts/*' node-version: 'lts/*'
cache: 'npm' cache: 'npm'
@@ -51,14 +51,14 @@ jobs:
fingerprint: ${{ vars.GPG_FINGERPRINT }} fingerprint: ${{ vars.GPG_FINGERPRINT }}
- name: Release - name: Release
uses: cycjimmy/semantic-release-action@v4 uses: cycjimmy/semantic-release-action@v5
id: release id: release
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Attest - name: Attest
if: steps.release.outputs.new_release_published == 'true' if: steps.release.outputs.new_release_published == 'true'
uses: actions/attest-build-provenance@v2 uses: actions/attest-build-provenance@v3
with: with:
subject-name: 'ReVanced Patches ${{ steps.release.outputs.new_release_git_tag }}' subject-name: 'ReVanced Patches ${{ steps.release.outputs.new_release_git_tag }}'
subject-path: patches/build/libs/patches-*.rvp subject-path: patches/build/libs/patches-*.rvp

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: Update Gradle Wrapper - name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v1 uses: gradle-update/update-gradle-wrapper-action@v1

View File

@@ -1,3 +1,247 @@
# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14)
### Bug Fixes
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
# [5.43.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.3...v5.43.0-dev.1) (2025-10-11)
### Features
* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b))
## [5.42.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.2...v5.42.2-dev.3) (2025-10-11)
### Bug Fixes
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](https://github.com/ReVanced/revanced-patches/commit/6555f6e6f8b52c2f1ddab1f52c6704cd2d8cfc12))
## [5.42.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.1...v5.42.2-dev.2) (2025-10-10)
### Bug Fixes
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](https://github.com/ReVanced/revanced-patches/commit/54846253d748f4e7e30b2bba427c7d2fb9c341e2))
## [5.42.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.42.2-dev.1) (2025-10-09)
### Bug Fixes
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](https://github.com/ReVanced/revanced-patches/commit/be2b144cc9c4108ec37e16f3dd20573d88ffaa2b))
## [5.42.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1) (2025-10-08)
### Bug Fixes
* **YouTube - Custom Branding:** Resolve startup crash with root installation ([fd4b2e1](https://github.com/ReVanced/revanced-patches/commit/fd4b2e1bb98c6e507178e5b46b896ef7d320bc3d))
## [5.42.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1-dev.1) (2025-10-08)
### Bug Fixes
* **YouTube - Custom Branding:** Resolve startup crash with root installation ([fd4b2e1](https://github.com/ReVanced/revanced-patches/commit/fd4b2e1bb98c6e507178e5b46b896ef7d320bc3d))
# [5.42.0](https://github.com/ReVanced/revanced-patches/compare/v5.41.0...v5.42.0) (2025-10-08)
### Bug Fixes
* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](https://github.com/ReVanced/revanced-patches/commit/9441e7acb4817e12d1443d438ef6c448518bd614))
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](https://github.com/ReVanced/revanced-patches/commit/ae4b9474d3fb62528fc21397c19954d31605e9da))
* **Instagram - Hide navigation buttons:** Resolve app startup crash ([080a226](https://github.com/ReVanced/revanced-patches/commit/080a2266146798be71789c939deef2f289697523))
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](https://github.com/ReVanced/revanced-patches/commit/19949e1695cc252ff0f94a33b6e3fb62e967d7fd))
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](https://github.com/ReVanced/revanced-patches/commit/673609c2aa87988cdc138eab101b9750fe6a7b62))
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](https://github.com/ReVanced/revanced-patches/commit/bd4ba2dae85ee6fd8d7e6078c3de775ca336e0b6))
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](https://github.com/ReVanced/revanced-patches/commit/9d6731660ba0e19b863d05d54aa04f74a879f69b))
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](https://github.com/ReVanced/revanced-patches/commit/76b0364c5b5562c6a0d178d2bbe5b220f48aaca9))
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](https://github.com/ReVanced/revanced-patches/commit/f03256c471e1ee6a12267c1b56b531ca8f89278c))
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](https://github.com/ReVanced/revanced-patches/commit/7afeaebb5cc22eb4f4512d8aa0cf4e835e7a2daf))
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](https://github.com/ReVanced/revanced-patches/commit/a62ee43441b197f5c8352ae373bb8919ad66f0bd))
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](https://github.com/ReVanced/revanced-patches/commit/328234f39ada81542e596f04e8ce410c787c15c8))
* **YouTube Music - Hide cast button:** Fix patching error ([28799a5](https://github.com/ReVanced/revanced-patches/commit/28799a548a73651134ef304cb6cb542cf8e55abe))
* **YouTube Music - Hide cast button:** Resolve button not hiding ([7817885](https://github.com/ReVanced/revanced-patches/commit/7817885cffed66608039ab45881537cbd3069c9d))
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](https://github.com/ReVanced/revanced-patches/commit/6b2634691423f5ce25a28b3f2fbc420977b81748))
### Features
* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](https://github.com/ReVanced/revanced-patches/commit/a50f3b5177808f07d84041c946caccb5a08ad387))
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](https://github.com/ReVanced/revanced-patches/commit/20c413120bad97af6121718e76b22a1b5540aa44))
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](https://github.com/ReVanced/revanced-patches/commit/2154d89242fd8d7f7460145d5d35a4f1986944a3))
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](https://github.com/ReVanced/revanced-patches/commit/08e8ead04ffff47a4608a3db7aadc8d5feccd4ad))
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](https://github.com/ReVanced/revanced-patches/commit/963a4ef43fd513de7a2d7d019992f06b62fdcc10))
* **Viber:** Add `Hide navigation buttons` patch ([#5991](https://github.com/ReVanced/revanced-patches/issues/5991)) ([5cb46c4](https://github.com/ReVanced/revanced-patches/commit/5cb46c4e9180ebc16eddb983dad73d137d8ec047))
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](https://github.com/ReVanced/revanced-patches/commit/4c8b56f5466b244737f501654eb7c5d34b6b2f88))
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](https://github.com/ReVanced/revanced-patches/commit/d0d53d109e451759a029326873adfa36fba12b23))
# [5.42.0](https://github.com/ReVanced/revanced-patches/compare/v5.41.0...v5.42.0) (2025-10-08)
### Bug Fixes
* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](https://github.com/ReVanced/revanced-patches/commit/9441e7acb4817e12d1443d438ef6c448518bd614))
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](https://github.com/ReVanced/revanced-patches/commit/ae4b9474d3fb62528fc21397c19954d31605e9da))
* **Instagram - Hide navigation buttons:** Resolve app startup crash ([080a226](https://github.com/ReVanced/revanced-patches/commit/080a2266146798be71789c939deef2f289697523))
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](https://github.com/ReVanced/revanced-patches/commit/19949e1695cc252ff0f94a33b6e3fb62e967d7fd))
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](https://github.com/ReVanced/revanced-patches/commit/673609c2aa87988cdc138eab101b9750fe6a7b62))
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](https://github.com/ReVanced/revanced-patches/commit/bd4ba2dae85ee6fd8d7e6078c3de775ca336e0b6))
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](https://github.com/ReVanced/revanced-patches/commit/9d6731660ba0e19b863d05d54aa04f74a879f69b))
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](https://github.com/ReVanced/revanced-patches/commit/76b0364c5b5562c6a0d178d2bbe5b220f48aaca9))
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](https://github.com/ReVanced/revanced-patches/commit/f03256c471e1ee6a12267c1b56b531ca8f89278c))
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](https://github.com/ReVanced/revanced-patches/commit/7afeaebb5cc22eb4f4512d8aa0cf4e835e7a2daf))
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](https://github.com/ReVanced/revanced-patches/commit/a62ee43441b197f5c8352ae373bb8919ad66f0bd))
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](https://github.com/ReVanced/revanced-patches/commit/328234f39ada81542e596f04e8ce410c787c15c8))
* **YouTube Music - Hide cast button:** Fix patching error ([28799a5](https://github.com/ReVanced/revanced-patches/commit/28799a548a73651134ef304cb6cb542cf8e55abe))
* **YouTube Music - Hide cast button:** Resolve button not hiding ([7817885](https://github.com/ReVanced/revanced-patches/commit/7817885cffed66608039ab45881537cbd3069c9d))
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](https://github.com/ReVanced/revanced-patches/commit/6b2634691423f5ce25a28b3f2fbc420977b81748))
### Features
* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](https://github.com/ReVanced/revanced-patches/commit/a50f3b5177808f07d84041c946caccb5a08ad387))
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](https://github.com/ReVanced/revanced-patches/commit/20c413120bad97af6121718e76b22a1b5540aa44))
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](https://github.com/ReVanced/revanced-patches/commit/2154d89242fd8d7f7460145d5d35a4f1986944a3))
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](https://github.com/ReVanced/revanced-patches/commit/08e8ead04ffff47a4608a3db7aadc8d5feccd4ad))
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](https://github.com/ReVanced/revanced-patches/commit/963a4ef43fd513de7a2d7d019992f06b62fdcc10))
* **Viber:** Add `Hide navigation buttons` patch ([#5991](https://github.com/ReVanced/revanced-patches/issues/5991)) ([5cb46c4](https://github.com/ReVanced/revanced-patches/commit/5cb46c4e9180ebc16eddb983dad73d137d8ec047))
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](https://github.com/ReVanced/revanced-patches/commit/4c8b56f5466b244737f501654eb7c5d34b6b2f88))
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](https://github.com/ReVanced/revanced-patches/commit/d0d53d109e451759a029326873adfa36fba12b23))
# [5.42.0-dev.19](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.18...v5.42.0-dev.19) (2025-10-07)
### Bug Fixes
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](https://github.com/ReVanced/revanced-patches/commit/7afeaebb5cc22eb4f4512d8aa0cf4e835e7a2daf))
# [5.42.0-dev.18](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.17...v5.42.0-dev.18) (2025-10-07)
### Features
* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](https://github.com/ReVanced/revanced-patches/commit/a50f3b5177808f07d84041c946caccb5a08ad387))
# [5.42.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.16...v5.42.0-dev.17) (2025-10-07)
### Bug Fixes
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](https://github.com/ReVanced/revanced-patches/commit/bd4ba2dae85ee6fd8d7e6078c3de775ca336e0b6))
# [5.42.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.15...v5.42.0-dev.16) (2025-10-07)
### Bug Fixes
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](https://github.com/ReVanced/revanced-patches/commit/f03256c471e1ee6a12267c1b56b531ca8f89278c))
# [5.42.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.14...v5.42.0-dev.15) (2025-10-07)
### Features
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](https://github.com/ReVanced/revanced-patches/commit/2154d89242fd8d7f7460145d5d35a4f1986944a3))
# [5.42.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.13...v5.42.0-dev.14) (2025-10-07)
### Features
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](https://github.com/ReVanced/revanced-patches/commit/20c413120bad97af6121718e76b22a1b5540aa44))
# [5.42.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.12...v5.42.0-dev.13) (2025-10-07)
### Bug Fixes
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](https://github.com/ReVanced/revanced-patches/commit/19949e1695cc252ff0f94a33b6e3fb62e967d7fd))
# [5.42.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.11...v5.42.0-dev.12) (2025-10-03)
### Bug Fixes
* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](https://github.com/ReVanced/revanced-patches/commit/9441e7acb4817e12d1443d438ef6c448518bd614))
### Features
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](https://github.com/ReVanced/revanced-patches/commit/963a4ef43fd513de7a2d7d019992f06b62fdcc10))
# [5.42.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.10...v5.42.0-dev.11) (2025-10-03)
### Bug Fixes
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](https://github.com/ReVanced/revanced-patches/commit/6b2634691423f5ce25a28b3f2fbc420977b81748))
# [5.42.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.9...v5.42.0-dev.10) (2025-10-02)
### Bug Fixes
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](https://github.com/ReVanced/revanced-patches/commit/a62ee43441b197f5c8352ae373bb8919ad66f0bd))
# [5.42.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.8...v5.42.0-dev.9) (2025-10-01)
### Bug Fixes
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](https://github.com/ReVanced/revanced-patches/commit/ae4b9474d3fb62528fc21397c19954d31605e9da))
# [5.42.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.7...v5.42.0-dev.8) (2025-10-01)
### Bug Fixes
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](https://github.com/ReVanced/revanced-patches/commit/9d6731660ba0e19b863d05d54aa04f74a879f69b))
### Features
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](https://github.com/ReVanced/revanced-patches/commit/d0d53d109e451759a029326873adfa36fba12b23))
# [5.42.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.6...v5.42.0-dev.7) (2025-10-01)
### Features
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](https://github.com/ReVanced/revanced-patches/commit/08e8ead04ffff47a4608a3db7aadc8d5feccd4ad))
# [5.42.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.5...v5.42.0-dev.6) (2025-09-30)
### Bug Fixes
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](https://github.com/ReVanced/revanced-patches/commit/673609c2aa87988cdc138eab101b9750fe6a7b62))
# [5.42.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.4...v5.42.0-dev.5) (2025-09-28)
### Features
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](https://github.com/ReVanced/revanced-patches/commit/4c8b56f5466b244737f501654eb7c5d34b6b2f88))
# [5.42.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.3...v5.42.0-dev.4) (2025-09-28)
### Bug Fixes
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](https://github.com/ReVanced/revanced-patches/commit/328234f39ada81542e596f04e8ce410c787c15c8))
# [5.42.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.2...v5.42.0-dev.3) (2025-09-28)
### Bug Fixes
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](https://github.com/ReVanced/revanced-patches/commit/76b0364c5b5562c6a0d178d2bbe5b220f48aaca9))
# [5.42.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.1...v5.42.0-dev.2) (2025-09-27) # [5.42.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.1...v5.42.0-dev.2) (2025-09-27)

View File

@@ -0,0 +1,30 @@
package app.revanced.extension.instagram.misc.links;
import android.net.Uri;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
@SuppressWarnings("unused")
public final class OpenLinksExternallyPatch {
/**
* Injection point.
*/
public static boolean openExternally(String url) {
try {
// The "url" parameter to this function will be of the form.
// https://l.instagram.com/?u=<actual url>&e=<tracking id>
String actualUrl = Uri.parse(url).getQueryParameter("u");
if (actualUrl != null) {
Utils.openLink(actualUrl);
return true;
}
} catch (Exception ex) {
Logger.printException(() -> "openExternally failure", ex);
}
return false;
}
}

View File

@@ -0,0 +1,15 @@
package app.revanced.extension.instagram.misc.privacy;
import app.revanced.extension.shared.privacy.LinkSanitizer;
@SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch {
private static final LinkSanitizer sanitizer = new LinkSanitizer("igsh");
/**
* Injection point.
*/
public static String sanitizeSharingLink(String url) {
return sanitizer.sanitizeUrlString(url);
}
}

View File

@@ -0,0 +1,33 @@
package app.revanced.extension.instagram.misc.share.domain;
import android.net.Uri;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public final class ChangeLinkSharingDomainPatch {
private static String getCustomShareDomain() {
// Method is modified during patching.
throw new IllegalStateException();
}
/**
* Injection point.
*/
public static String setCustomShareDomain(String url) {
try {
Uri uri = Uri.parse(url);
Uri.Builder builder = uri
.buildUpon()
.authority(getCustomShareDomain())
.clearQuery();
String patchedUrl = builder.build().toString();
Logger.printInfo(() -> "Domain change from : " + url + " to: " + patchedUrl);
return patchedUrl;
} catch (Exception ex) {
Logger.printException(() -> "setCustomShareDomain failure with " + url, ex);
return url;
}
}
}

View File

@@ -0,0 +1,15 @@
package app.revanced.extension.instagram.misc.share.privacy;
import app.revanced.extension.shared.privacy.LinkSanitizer;
@SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch {
private static final LinkSanitizer sanitizer = new LinkSanitizer("igsh");
/**
* Injection point.
*/
public static String sanitizeSharingLink(String url) {
return sanitizer.sanitizeUrlString(url);
}
}

View File

@@ -0,0 +1,17 @@
package app.revanced.extension.music.patches;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class ForceOriginalAudioPatch {
/**
* Injection point.
*/
public static void setEnabled() {
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
Settings.FORCE_ORIGINAL_AUDIO.get(),
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
);
}
}

View File

@@ -32,4 +32,6 @@ public class Settings extends BaseSettings {
// Miscellaneous // Miscellaneous
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS)); ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
} }

View File

@@ -5,8 +5,10 @@ import android.preference.PreferenceScreen;
import android.widget.Toolbar; import android.widget.Toolbar;
import app.revanced.extension.music.settings.MusicActivityHook; import app.revanced.extension.music.settings.MusicActivityHook;
import app.revanced.extension.shared.GmsCoreSupport;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment; import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
/** /**
@@ -30,6 +32,17 @@ public class MusicPreferenceFragment extends ToolbarPreferenceFragment {
preferenceScreen = getPreferenceScreen(); preferenceScreen = getPreferenceScreen();
Utils.sortPreferenceGroups(preferenceScreen); Utils.sortPreferenceGroups(preferenceScreen);
setPreferenceScreenToolbar(preferenceScreen); setPreferenceScreenToolbar(preferenceScreen);
// Clunky work around until preferences are custom classes that manage themselves.
// Custom branding only works with non-root install. But the preferences must be
// added during patched because of difficulties detecting during patching if it's
// a root install. So instead the non-functional preferences are removed during
// runtime if the app is mount (root) installation.
if (GmsCoreSupport.isPackageNameOriginal()) {
removePreferences(
BaseSettings.CUSTOM_BRANDING_ICON.key,
BaseSettings.CUSTOM_BRANDING_NAME.key);
}
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex); Logger.printException(() -> "initialize failure", ex);
} }

View File

@@ -31,9 +31,6 @@ import app.revanced.extension.shared.ui.CustomDialog;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class GmsCoreSupport { public class GmsCoreSupport {
private static final String PACKAGE_NAME_YOUTUBE = "com.google.android.youtube";
private static final String PACKAGE_NAME_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music";
private static final String GMS_CORE_PACKAGE_NAME private static final String GMS_CORE_PACKAGE_NAME
= getGmsCoreVendorGroupId() + ".android.gms"; = getGmsCoreVendorGroupId() + ".android.gms";
private static final Uri GMS_CORE_PROVIDER private static final Uri GMS_CORE_PROVIDER
@@ -53,6 +50,20 @@ public class GmsCoreSupport {
@Nullable @Nullable
private static volatile Boolean DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED; private static volatile Boolean DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED;
private static String getOriginalPackageName() {
return null; // Modified during patching.
}
/**
* @return If the current package name is the same as the original unpatched app.
* If `GmsCore support` was not included during patching, this returns true;
*/
public static boolean isPackageNameOriginal() {
String originalPackageName = getOriginalPackageName();
return originalPackageName == null
|| originalPackageName.equals(Utils.getContext().getPackageName());
}
private static void open(String queryOrLink) { private static void open(String queryOrLink) {
Logger.printInfo(() -> "Opening link: " + queryOrLink); Logger.printInfo(() -> "Opening link: " + queryOrLink);
@@ -113,11 +124,10 @@ public class GmsCoreSupport {
// Verify the user has not included GmsCore for a root installation. // Verify the user has not included GmsCore for a root installation.
// GmsCore Support changes the package name, but with a mounted installation // GmsCore Support changes the package name, but with a mounted installation
// all manifest changes are ignored and the original package name is used. // all manifest changes are ignored and the original package name is used.
String packageName = context.getPackageName(); if (isPackageNameOriginal()) {
if (packageName.equals(PACKAGE_NAME_YOUTUBE) || packageName.equals(PACKAGE_NAME_YOUTUBE_MUSIC)) {
Logger.printInfo(() -> "App is mounted with root, but GmsCore patch was included"); Logger.printInfo(() -> "App is mounted with root, but GmsCore patch was included");
// Cannot use localize text here, since the app will load // Cannot use localize text here, since the app will load resources
// resources from the unpatched app and all patch strings are missing. // from the unpatched app and all patch strings are missing.
Utils.showToastLong("The 'GmsCore support' patch breaks mount installations"); Utils.showToastLong("The 'GmsCore support' patch breaks mount installations");
// Do not exit. If the app exits before launch completes (and without // Do not exit. If the app exits before launch completes (and without
@@ -250,8 +260,7 @@ public class GmsCoreSupport {
}; };
} }
// Modified by a patch. Do not touch.
private static String getGmsCoreVendorGroupId() { private static String getGmsCoreVendorGroupId() {
return "app.revanced"; return "app.revanced"; // Modified during patching.
} }
} }

View File

@@ -15,6 +15,7 @@ import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@@ -696,6 +697,18 @@ public class Utils {
} }
} }
public static void openLink(String url) {
try {
Intent intent = new Intent("android.intent.action.VIEW", Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Logger.printInfo(() -> "Opening link with external browser: " + intent);
getContext().startActivity(intent);
} catch (Exception ex) {
Logger.printException(() -> "openLink failure", ex);
}
}
public enum NetworkType { public enum NetworkType {
NONE, NONE,
MOBILE, MOBILE,

View File

@@ -46,7 +46,7 @@ public class CheckWatchHistoryDomainNameResolutionPatch {
/** /**
* Injection point. * Injection point.
* *
* Checks if s.youtube.com is blacklisted and playback history will fail to work. * Checks if YouTube watch history endpoint cannot be reached.
*/ */
public static void checkDnsResolver(Activity context) { public static void checkDnsResolver(Activity context) {
if (!Utils.isNetworkConnected() || !BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return; if (!Utils.isNetworkConnected() || !BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return;
@@ -67,28 +67,20 @@ public class CheckWatchHistoryDomainNameResolutionPatch {
} }
Utils.runOnMainThread(() -> { Utils.runOnMainThread(() -> {
try { Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create(
// Create the custom dialog. context,
Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create( str("revanced_check_watch_history_domain_name_dialog_title"), // Title.
context, Html.fromHtml(str("revanced_check_watch_history_domain_name_dialog_message")), // Message (HTML).
str("revanced_check_watch_history_domain_name_dialog_title"), // Title. null, // No EditText.
Html.fromHtml(str("revanced_check_watch_history_domain_name_dialog_message")), // Message (HTML). null, // OK button text.
null, // No EditText. () -> {}, // OK button action (just dismiss).
null, // OK button text. null, // No cancel button.
() -> {}, // OK button action (just dismiss). str("revanced_check_watch_history_domain_name_dialog_ignore"), // Neutral button text.
() -> {}, // Cancel button action (just dismiss). () -> BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore).
str("revanced_check_watch_history_domain_name_dialog_ignore"), // Neutral button text. true // Dismiss dialog on Neutral button click.
() -> BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore). );
true // Dismiss dialog on Neutral button click.
);
// Show the dialog. Utils.showDialog(context, dialogPair.first, false, null);
Dialog dialog = dialogPair.first;
Utils.showDialog(context, dialog, false, null);
} catch (Exception ex) {
Logger.printException(() -> "checkDnsResolver dialog creation failure", ex);
}
}); });
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "checkDnsResolver failure", ex); Logger.printException(() -> "checkDnsResolver failure", ex);

View File

@@ -0,0 +1,167 @@
package app.revanced.extension.shared.patches;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import app.revanced.extension.shared.GmsCoreSupport;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
/**
* Patch shared by YouTube and YT Music.
*/
@SuppressWarnings("unused")
public class CustomBrandingPatch {
// Important: In the future, additional branding themes can be added but all existing and prior
// themes cannot be removed or renamed.
//
// This is because if a user has a branding theme selected, then only that launch alias is enabled.
// If a future update removes or renames that alias, then after updating the app is effectively
// broken and it cannot be opened and not even clearing the app data will fix it.
// In that situation the only fix is to completely uninstall and reinstall again.
//
// The most that can be done is to hide a theme from the UI and keep the alias with dummy data.
public enum BrandingTheme {
/**
* Original unpatched icon.
*/
ORIGINAL,
ROUNDED,
MINIMAL,
SCALED,
/**
* User provided custom icon.
*/
CUSTOM;
private String packageAndNameIndexToClassAlias(String packageName, int appIndex) {
if (appIndex <= 0) {
throw new IllegalArgumentException("App index starts at index 1");
}
return packageName + ".revanced_" + name().toLowerCase(Locale.US) + '_' + appIndex;
}
}
private static final int notificationSmallIcon;
static {
BrandingTheme branding = BaseSettings.CUSTOM_BRANDING_ICON.get();
if (branding == BrandingTheme.ORIGINAL) {
notificationSmallIcon = 0;
} else {
// Original icon is quantum_ic_video_youtube_white_24
String iconName = "revanced_notification_icon";
if (branding == BrandingTheme.CUSTOM) {
iconName += "_custom";
}
notificationSmallIcon = Utils.getResourceIdentifier(iconName, "drawable");
if (notificationSmallIcon == 0) {
Logger.printException(() -> "Could not load notification small icon");
}
}
}
/**
* Injection point.
*/
public static void setNotificationIcon(Notification.Builder builder) {
try {
if (notificationSmallIcon != 0) {
builder.setSmallIcon(notificationSmallIcon)
.setColor(Color.TRANSPARENT); // Remove YT red tint.
}
} catch (Exception ex) {
Logger.printException(() -> "setNotificationIcon failure", ex);
}
}
/**
* Injection point.
*
* The total number of app name aliases, including dummy aliases.
*/
private static int numberOfPresetAppNames() {
// Modified during patching.
throw new IllegalStateException();
}
/**
* Injection point.
*/
@SuppressWarnings("ConstantConditions")
public static void setBranding() {
try {
if (GmsCoreSupport.isPackageNameOriginal()) {
Logger.printInfo(() -> "App is root mounted. Cannot dynamically change app icon");
return;
}
Context context = Utils.getContext();
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
BrandingTheme selectedBranding = BaseSettings.CUSTOM_BRANDING_ICON.get();
final int selectedNameIndex = BaseSettings.CUSTOM_BRANDING_NAME.get();
ComponentName componentToEnable = null;
ComponentName defaultComponent = null;
List<ComponentName> componentsToDisable = new ArrayList<>();
for (BrandingTheme theme : BrandingTheme.values()) {
// Must always update all aliases including custom alias (last index).
final int numberOfPresetAppNames = numberOfPresetAppNames();
// App name indices starts at 1.
for (int index = 1; index <= numberOfPresetAppNames; index++) {
String aliasClass = theme.packageAndNameIndexToClassAlias(packageName, index);
ComponentName component = new ComponentName(packageName, aliasClass);
if (defaultComponent == null) {
// Default is always the first alias.
defaultComponent = component;
}
if (index == selectedNameIndex && theme == selectedBranding) {
componentToEnable = component;
} else {
componentsToDisable.add(component);
}
}
}
if (componentToEnable == null) {
// User imported a bad app name index value. Either the imported data
// was corrupted, or they previously had custom name enabled and the app
// no longer has a custom name specified.
Utils.showToastLong("Custom branding reset");
BaseSettings.CUSTOM_BRANDING_ICON.resetToDefault();
BaseSettings.CUSTOM_BRANDING_NAME.resetToDefault();
componentToEnable = defaultComponent;
componentsToDisable.remove(defaultComponent);
}
for (ComponentName disable : componentsToDisable) {
// Use info logging because if the alias status become corrupt the app cannot launch.
Logger.printInfo(() -> "Disabling: " + disable.getClassName());
pm.setComponentEnabledSetting(disable,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
ComponentName componentToEnableFinal = componentToEnable;
Logger.printInfo(() -> "Enabling: " + componentToEnableFinal.getClassName());
pm.setComponentEnabledSetting(componentToEnable,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
} catch (Exception ex) {
Logger.printException(() -> "setBranding failure", ex);
}
}
}

View File

@@ -0,0 +1,71 @@
package app.revanced.extension.shared.patches;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
@SuppressWarnings("unused")
public class ForceOriginalAudioPatch {
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
private static volatile boolean enabled;
public static void setEnabled(boolean isEnabled, ClientType client) {
enabled = isEnabled;
if (isEnabled && !client.useAuth && !client.supportsMultiAudioTracks) {
// If client spoofing does not use authentication and lacks multi-audio streams,
// then can use any language code for the request and if that requested language is
// not available YT uses the original audio language. Authenticated requests ignore
// the language code and always use the account language. Use a language that is
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
// but the language is also supported natively by the Meta Quest device that
// Android VR is spoofing.
AppLanguage override = AppLanguage.NB; // Norwegian Bokmal.
Logger.printDebug(() -> "Setting language override: " + override);
SpoofVideoStreamsPatch.setLanguageOverride(override);
}
}
/**
* Injection point.
*/
public static boolean ignoreDefaultAudioStream(boolean original) {
if (enabled) {
return false;
}
return original;
}
/**
* Injection point.
*/
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
try {
if (!enabled) {
return isDefault;
}
if (audioTrackId.isEmpty()) {
// Older app targets can have empty audio tracks and these might be placeholders.
// The real audio tracks are called after these.
return isDefault;
}
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
if (isOriginal) {
Logger.printDebug(() -> "Using audio: " + audioTrackId);
}
return isOriginal;
} catch (Exception ex) {
Logger.printException(() -> "isDefaultAudioStream failure", ex);
return isDefault;
}
}
}

View File

@@ -1,5 +1,6 @@
package app.revanced.extension.shared.patches; package app.revanced.extension.shared.patches;
import app.revanced.extension.shared.privacy.LinkSanitizer;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
/** /**
@@ -7,17 +8,18 @@ import app.revanced.extension.shared.settings.BaseSettings;
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch { public final class SanitizeSharingLinksPatch {
private static final String NEW_TRACKING_PARAMETER_REGEX = ".si=.+";
private static final String OLD_TRACKING_PARAMETER_REGEX = ".feature=.+"; private static final LinkSanitizer sanitizer = new LinkSanitizer(
"si",
"feature" // Old tracking parameter name, and may be obsolete.
);
/** /**
* Injection point. * Injection point.
*/ */
public static String sanitize(String url) { public static String sanitize(String url) {
if (BaseSettings.SANITIZE_SHARED_LINKS.get()) { if (BaseSettings.SANITIZE_SHARED_LINKS.get()) {
url = url url = sanitizer.sanitizeUrlString(url);
.replaceAll(NEW_TRACKING_PARAMETER_REGEX, "")
.replaceAll(OLD_TRACKING_PARAMETER_REGEX, "");
} }
if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) { if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) {

View File

@@ -0,0 +1,60 @@
package app.revanced.extension.shared.privacy;
import android.net.Uri;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import app.revanced.extension.shared.Logger;
/**
* Strips away specific parameters from URLs.
*/
public class LinkSanitizer {
private final Collection<String> parametersToRemove;
public LinkSanitizer(String ... parametersToRemove) {
final int parameterCount = parametersToRemove.length;
if (parameterCount == 0) {
throw new IllegalArgumentException("No parameters specified");
}
// List is faster if only checking a few parameters.
this.parametersToRemove = parameterCount > 4
? Set.of(parametersToRemove)
: List.of(parametersToRemove);
}
public String sanitizeUrlString(String url) {
try {
return sanitizeUri(Uri.parse(url)).toString();
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUrlString failure: " + url, ex);
return url;
}
}
public Uri sanitizeUri(Uri uri) {
try {
Uri.Builder builder = uri.buildUpon().clearQuery();
for (String paramName : uri.getQueryParameterNames()) {
if (!parametersToRemove.contains(paramName)) {
for (String value : uri.getQueryParameters(paramName)) {
builder.appendQueryParameter(paramName, value);
}
}
}
Uri sanitizedUrl = builder.build();
Logger.printInfo(() -> "Sanitized url: " + uri + " to: " + sanitizedUrl);
return sanitizedUrl;
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUri failure: " + uri, ex);
return uri;
}
}
}

View File

@@ -36,8 +36,8 @@ public enum AppLanguage {
FR, FR,
GL, GL,
GU, GU,
HI,
HE, // App uses obsolete 'IW' and not the modern 'HE' ISO code. HE, // App uses obsolete 'IW' and not the modern 'HE' ISO code.
HI,
HR, HR,
HU, HU,
HY, HY,
@@ -60,9 +60,9 @@ public enum AppLanguage {
MR, MR,
MS, MS,
MY, MY,
NB,
NE, NE,
NL, NL,
NB,
OR, OR,
PA, PA,
PL, PL,

View File

@@ -2,6 +2,7 @@ package app.revanced.extension.shared.settings;
import static java.lang.Boolean.FALSE; import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.patches.CustomBrandingPatch.BrandingTheme;
import static app.revanced.extension.shared.settings.Setting.parent; import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability; import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
@@ -40,4 +41,7 @@ public class BaseSettings {
public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE); public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE);
public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false); public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false);
public static final EnumSetting<BrandingTheme> CUSTOM_BRANDING_ICON = new EnumSetting<>("revanced_custom_branding_icon", BrandingTheme.ORIGINAL, true);
public static final IntegerSetting CUSTOM_BRANDING_NAME = new IntegerSetting("revanced_custom_branding_name", 1, true);
} }

View File

@@ -1,4 +1,4 @@
package app.revanced.extension.youtube.settings.preference; package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str; import static app.revanced.extension.shared.StringRef.str;
@@ -6,17 +6,17 @@ import android.content.Context;
import android.preference.SwitchPreference; import android.preference.SwitchPreference;
import android.util.AttributeSet; import android.util.AttributeSet;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch; import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings({"deprecation", "unused"}) @SuppressWarnings({"deprecation", "unused"})
public class ForceOriginalAudioSwitchPreference extends SwitchPreference { public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
// Spoof stream patch is not included, or is not currently spoofing to Android Studio. // Spoof stream patch is not included, or is not currently spoofing to Android Studio.
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded() private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|| !(Settings.SPOOF_VIDEO_STREAMS.get() || !(BaseSettings.SPOOF_VIDEO_STREAMS.get()
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR); && SpoofVideoStreamsPatch.getPreferredClient() == ClientType.ANDROID_CREATOR);
{ {
if (!available) { if (!available) {

View File

@@ -5,6 +5,7 @@ import static app.revanced.extension.shared.Utils.dipToPixels;
import static app.revanced.extension.shared.requests.Route.Method.GET; import static app.revanced.extension.shared.requests.Route.Method.GET;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
@@ -125,6 +126,8 @@ public class ReVancedAboutPreference extends Preference {
{ {
setOnPreferenceClickListener(pref -> { setOnPreferenceClickListener(pref -> {
Context context = pref.getContext();
// Show a progress spinner if the social links are not fetched yet. // Show a progress spinner if the social links are not fetched yet.
if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) { if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
// Show a progress spinner, but only if the api fetch takes more than a half a second. // Show a progress spinner, but only if the api fetch takes more than a half a second.
@@ -137,17 +140,18 @@ public class ReVancedAboutPreference extends Preference {
handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner); handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner);
Utils.runOnBackgroundThread(() -> Utils.runOnBackgroundThread(() ->
fetchLinksAndShowDialog(handler, showDialogRunnable, progress)); fetchLinksAndShowDialog(context, handler, showDialogRunnable, progress));
} else { } else {
// No network call required and can run now. // No network call required and can run now.
fetchLinksAndShowDialog(null, null, null); fetchLinksAndShowDialog(context, null, null, null);
} }
return false; return false;
}); });
} }
private void fetchLinksAndShowDialog(@Nullable Handler handler, private void fetchLinksAndShowDialog(Context context,
@Nullable Handler handler,
Runnable showDialogRunnable, Runnable showDialogRunnable,
@Nullable ProgressDialog progress) { @Nullable ProgressDialog progress) {
WebLink[] links = AboutLinksRoutes.fetchAboutLinks(); WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
@@ -164,7 +168,17 @@ public class ReVancedAboutPreference extends Preference {
if (handler != null) { if (handler != null) {
handler.removeCallbacks(showDialogRunnable); handler.removeCallbacks(showDialogRunnable);
} }
if (progress != null) {
// Don't continue if the activity is done. To test this tap the
// about dialog and immediately press back before the dialog can show.
if (context instanceof Activity activity) {
if (activity.isFinishing() || activity.isDestroyed()) {
Logger.printDebug(() -> "Not showing about dialog, activity is closed");
return;
}
}
if (progress != null && progress.isShowing()) {
progress.dismiss(); progress.dismiss();
} }
new WebViewDialog(getContext(), htmlDialog).show(); new WebViewDialog(getContext(), htmlDialog).show();

View File

@@ -6,6 +6,7 @@ import android.graphics.Insets;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -22,6 +23,24 @@ import app.revanced.extension.shared.settings.BaseActivityHook;
@SuppressWarnings({"deprecation", "NewApi"}) @SuppressWarnings({"deprecation", "NewApi"})
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment { public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
/**
* Removes the list of preferences from this fragment, if they exist.
* @param keys Preference keys.
*/
protected void removePreferences(String ... keys) {
for (String key : keys) {
Preference pref = findPreference(key);
if (pref != null) {
PreferenceGroup parent = pref.getParent();
if (parent != null) {
Logger.printDebug(() -> "Removing preference: " + key);
parent.removePreference(pref);
}
}
}
}
/** /**
* Sets toolbar for all nested preference screens. * Sets toolbar for all nested preference screens.
*/ */

View File

@@ -31,6 +31,7 @@ public enum ClientType {
"132.0.6808.3", "132.0.6808.3",
"1.61.48", "1.61.48",
false, false,
false,
"Android VR 1.61" "Android VR 1.61"
), ),
/** /**
@@ -50,6 +51,7 @@ public enum ClientType {
"107.0.5284.2", "107.0.5284.2",
"1.43.32", "1.43.32",
ANDROID_VR_1_61_48.useAuth, ANDROID_VR_1_61_48.useAuth,
ANDROID_VR_1_61_48.supportsMultiAudioTracks,
"Android VR 1.43" "Android VR 1.43"
), ),
/** /**
@@ -69,6 +71,7 @@ public enum ClientType {
"132.0.6779.0", "132.0.6779.0",
"23.47.101", "23.47.101",
true, true,
false,
"Android Studio" "Android Studio"
), ),
/** /**
@@ -83,6 +86,7 @@ public enum ClientType {
"0.1", "0.1",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
false, false,
false,
"visionOS" "visionOS"
), ),
/** /**
@@ -107,6 +111,7 @@ public enum ClientType {
"19.22.3", "19.22.3",
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")", "com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
false, false,
true,
"iPadOS" "iPadOS"
); );
@@ -180,6 +185,11 @@ public enum ClientType {
*/ */
public final boolean useAuth; public final boolean useAuth;
/**
* If the client supports multiple audio tracks.
*/
public final boolean supportsMultiAudioTracks;
/** /**
* Friendly name displayed in stats for nerds. * Friendly name displayed in stats for nerds.
*/ */
@@ -200,6 +210,7 @@ public enum ClientType {
@NonNull String cronetVersion, @NonNull String cronetVersion,
String clientVersion, String clientVersion,
boolean useAuth, boolean useAuth,
boolean supportsMultiAudioTracks,
String friendlyName) { String friendlyName) {
this.id = id; this.id = id;
this.clientName = clientName; this.clientName = clientName;
@@ -213,6 +224,7 @@ public enum ClientType {
this.cronetVersion = cronetVersion; this.cronetVersion = cronetVersion;
this.clientVersion = clientVersion; this.clientVersion = clientVersion;
this.useAuth = useAuth; this.useAuth = useAuth;
this.supportsMultiAudioTracks = supportsMultiAudioTracks;
this.friendlyName = friendlyName; this.friendlyName = friendlyName;
Locale defaultLocale = Locale.getDefault(); Locale defaultLocale = Locale.getDefault();
@@ -238,6 +250,7 @@ public enum ClientType {
String clientVersion, String clientVersion,
String userAgent, String userAgent,
boolean useAuth, boolean useAuth,
boolean supportsMultiAudioTracks,
String friendlyName) { String friendlyName) {
this.id = id; this.id = id;
this.clientName = clientName; this.clientName = clientName;
@@ -248,6 +261,7 @@ public enum ClientType {
this.clientVersion = clientVersion; this.clientVersion = clientVersion;
this.userAgent = userAgent; this.userAgent = userAgent;
this.useAuth = useAuth; this.useAuth = useAuth;
this.supportsMultiAudioTracks = supportsMultiAudioTracks;
this.friendlyName = friendlyName; this.friendlyName = friendlyName;
this.packageName = null; this.packageName = null;
this.androidSdkVersion = null; this.androidSdkVersion = null;

View File

@@ -19,6 +19,14 @@ import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class SpoofVideoStreamsPatch { public class SpoofVideoStreamsPatch {
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
}
}
/** /**
* Domain used for internet connectivity verification. * Domain used for internet connectivity verification.
* It has an empty response body and is only used to check for a 204 response code. * It has an empty response body and is only used to check for a 204 response code.
@@ -39,7 +47,7 @@ public class SpoofVideoStreamsPatch {
@Nullable @Nullable
private static volatile AppLanguage languageOverride; private static volatile AppLanguage languageOverride;
private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_61_48; private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_43_32;
/** /**
* @return If this patch was included during patching. * @return If this patch was included during patching.
@@ -66,6 +74,10 @@ public class SpoofVideoStreamsPatch {
StreamingDataRequest.setClientOrderToUse(availableClients, client); StreamingDataRequest.setClientOrderToUse(availableClients, client);
} }
public static ClientType getPreferredClient() {
return preferredClient;
}
public static boolean spoofingToClientWithNoMultiAudioStreams() { public static boolean spoofingToClientWithNoMultiAudioStreams() {
return isPatchIncluded() return isPatchIncluded()
&& SPOOF_STREAMING_DATA && SPOOF_STREAMING_DATA
@@ -317,11 +329,4 @@ public class SpoofVideoStreamsPatch {
return videoFormat; return videoFormat;
} }
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
}
}
} }

View File

@@ -1,18 +1,11 @@
package app.revanced.extension.spotify.misc.privacy; package app.revanced.extension.spotify.misc.privacy;
import android.net.Uri; import app.revanced.extension.shared.privacy.LinkSanitizer;
import java.util.List;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch { public final class SanitizeSharingLinksPatch {
/** private static final LinkSanitizer sanitizer = new LinkSanitizer(
* Parameters that are considered undesirable and should be stripped away.
*/
private static final List<String> SHARE_PARAMETERS_TO_REMOVE = List.of(
"si", // Share tracking parameter. "si", // Share tracking parameter.
"utm_source" // Share source, such as "copy-link". "utm_source" // Share source, such as "copy-link".
); );
@@ -20,25 +13,7 @@ public final class SanitizeSharingLinksPatch {
/** /**
* Injection point. * Injection point.
*/ */
public static String sanitizeUrl(String url) { public static String sanitizeSharingLink(String url) {
try { return sanitizer.sanitizeUrlString(url);
Uri uri = Uri.parse(url);
Uri.Builder builder = uri.buildUpon().clearQuery();
for (String paramName : uri.getQueryParameterNames()) {
if (!SHARE_PARAMETERS_TO_REMOVE.contains(paramName)) {
for (String value : uri.getQueryParameters(paramName)) {
builder.appendQueryParameter(paramName, value);
}
}
}
String sanitizedUrl = builder.build().toString();
Logger.printInfo(() -> "Sanitized url " + url + " to " + sanitizedUrl);
return sanitizedUrl;
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUrl failure with " + url, ex);
return url;
}
} }
} }

View File

@@ -1 +1,3 @@
// Do not remove. Necessary for the extension plugin to be applied to the project. dependencies {
compileOnly(project(":extensions:shared:library"))
}

View File

@@ -1,16 +1,20 @@
package app.revanced.twitter.patches.links; package app.revanced.twitter.patches.links;
@SuppressWarnings("unused")
public final class ChangeLinkSharingDomainPatch { public final class ChangeLinkSharingDomainPatch {
private static final String DOMAIN_NAME = "https://fxtwitter.com";
private static final String LINK_FORMAT = "%s/%s/status/%s"; private static final String LINK_FORMAT = "%s/%s/status/%s";
public static String formatResourceLink(Object... formatArgs) { /**
String username = (String) formatArgs[0]; * Method is modified during patching. Do not change.
String tweetId = (String) formatArgs[1]; */
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId); private static String getShareDomain() {
return "";
} }
/**
* Injection point.
*/
public static String formatLink(long tweetId, String username) { public static String formatLink(long tweetId, String username) {
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId); return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
} }
} }

View File

@@ -2,11 +2,18 @@ package app.revanced.twitter.patches.links;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.Log;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
@Deprecated(forRemoval = true)
public final class OpenLinksWithAppChooserPatch { public final class OpenLinksWithAppChooserPatch {
/**
* Injection point.
*/
public static void openWithChooser(final Context context, final Intent intent) { public static void openWithChooser(final Context context, final Intent intent) {
Log.d("ReVanced", "Opening intent with chooser: " + intent); Logger.printInfo(() -> "Opening intent with chooser: " + intent);
intent.setAction("android.intent.action.VIEW"); intent.setAction("android.intent.action.VIEW");

View File

@@ -1,72 +1,17 @@
package app.revanced.extension.youtube.patches; package app.revanced.extension.youtube.patches;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ForceOriginalAudioPatch { public class ForceOriginalAudioPatch {
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
/** /**
* Injection point. * Injection point.
*/ */
public static void setPreferredLanguage() { public static void setEnabled() {
if (Settings.FORCE_ORIGINAL_AUDIO.get() app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams() Settings.FORCE_ORIGINAL_AUDIO.get(),
&& !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) { Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
// If client spoofing does not use authentication and lacks multi-audio streams, );
// then can use any language code for the request and if that requested language is
// not available YT uses the original audio language. Authenticated requests ignore
// the language code and always use the account language. Use a language that is
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
// but the language is also supported natively by the Meta Quest device that
// Android VR is spoofing.
AppLanguage override = AppLanguage.SV;
Logger.printDebug(() -> "Setting language override: " + override);
SpoofVideoStreamsPatch.setLanguageOverride(override);
}
}
/**
* Injection point.
*/
public static boolean ignoreDefaultAudioStream(boolean original) {
if (Settings.FORCE_ORIGINAL_AUDIO.get()) {
return false;
}
return original;
}
/**
* Injection point.
*/
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
try {
if (!Settings.FORCE_ORIGINAL_AUDIO.get()) {
return isDefault;
}
if (audioTrackId.isEmpty()) {
// Older app targets can have empty audio tracks and these might be placeholders.
// The real audio tracks are called after these.
return isDefault;
}
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
if (isOriginal) {
Logger.printDebug(() -> "Using audio: " + audioTrackId);
}
return isOriginal;
} catch (Exception ex) {
Logger.printException(() -> "isDefaultAudioStream failure", ex);
return isDefault;
}
} }
} }

View File

@@ -0,0 +1,24 @@
package app.revanced.extension.youtube.patches;
import android.view.View;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class HideEndScreenCardsPatch {
/**
* Injection point.
*/
public static void hideEndScreenCardView(View view) {
Utils.hideViewUnderCondition(Settings.HIDE_ENDSCREEN_CARDS, view);
}
/**
* Injection point.
*/
public static boolean hideEndScreenCards() {
return Settings.HIDE_ENDSCREEN_CARDS.get();
}
}

View File

@@ -1,14 +0,0 @@
package app.revanced.extension.youtube.patches;
import android.view.View;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class HideEndscreenCardsPatch {
//Used by app.revanced.patches.youtube.layout.hideendscreencards.bytecode.patch.HideEndscreenCardsPatch
public static void hideEndscreen(View view) {
if (!Settings.HIDE_ENDSCREEN_CARDS.get()) return;
view.setVisibility(View.GONE);
}
}

View File

@@ -131,11 +131,11 @@ public class ReturnYouTubeDislikePatch {
String conversionContextString = conversionContext.toString(); String conversionContextString = conversionContext.toString();
if (isRollingNumber && !conversionContextString.contains("video_action_bar.eml")) { if (isRollingNumber && !conversionContextString.contains("video_action_bar.e")) {
return original; return original;
} }
if (conversionContextString.contains("segmented_like_dislike_button.eml")) { if (conversionContextString.contains("segmented_like_dislike_button.e")) {
// Regular video. // Regular video.
ReturnYouTubeDislike videoData = currentVideoData; ReturnYouTubeDislike videoData = currentVideoData;
if (videoData == null) { if (videoData == null) {
@@ -153,12 +153,12 @@ public class ReturnYouTubeDislikePatch {
} }
if (Utils.containsAny(conversionContextString, if (Utils.containsAny(conversionContextString,
"|shorts_dislike_button.eml", "|reel_dislike_button.eml")) { "|shorts_dislike_button.e", "|reel_dislike_button.e")) {
return getShortsSpan(original, true); return getShortsSpan(original, true);
} }
if (Utils.containsAny(conversionContextString, if (Utils.containsAny(conversionContextString,
"|shorts_like_button.eml", "|reel_like_button.eml")) { "|shorts_like_button.e", "|reel_like_button.e")) {
if (!Utils.containsNumber(original)) { if (!Utils.containsNumber(original)) {
Logger.printDebug(() -> "Replacing hidden likes count"); Logger.printDebug(() -> "Replacing hidden likes count");
return getShortsSpan(original, false); return getShortsSpan(original, false);

View File

@@ -105,17 +105,17 @@ public final class AdsFilter extends Filter {
Settings.HIDE_VIEW_PRODUCTS_BANNER, Settings.HIDE_VIEW_PRODUCTS_BANNER,
"product_item", "product_item",
"products_in_video", "products_in_video",
"shopping_overlay.eml" // Video player overlay shopping links. "shopping_overlay.e" // Video player overlay shopping links.
); );
final var shoppingLinks = new StringFilterGroup( final var shoppingLinks = new StringFilterGroup(
Settings.HIDE_SHOPPING_LINKS, Settings.HIDE_SHOPPING_LINKS,
"shopping_description_shelf.eml" "shopping_description_shelf.e"
); );
playerShoppingShelf = new StringFilterGroup( playerShoppingShelf = new StringFilterGroup(
Settings.HIDE_CREATOR_STORE_SHELF, Settings.HIDE_CREATOR_STORE_SHELF,
"horizontal_shelf.eml" "horizontal_shelf.e"
); );
playerShoppingShelfBuffer = new ByteArrayFilterGroup( playerShoppingShelfBuffer = new ByteArrayFilterGroup(
@@ -131,7 +131,7 @@ public final class AdsFilter extends Filter {
final var merchandise = new StringFilterGroup( final var merchandise = new StringFilterGroup(
Settings.HIDE_MERCHANDISE_BANNERS, Settings.HIDE_MERCHANDISE_BANNERS,
"product_carousel", "product_carousel",
"shopping_carousel.eml" // Channel profile shopping shelf. "shopping_carousel.e" // Channel profile shopping shelf.
); );
final var selfSponsor = new StringFilterGroup( final var selfSponsor = new StringFilterGroup(

View File

@@ -14,7 +14,7 @@ public final class AdvancedVideoQualityMenuFilter extends Filter {
public AdvancedVideoQualityMenuFilter() { public AdvancedVideoQualityMenuFilter() {
addPathCallbacks(new StringFilterGroup( addPathCallbacks(new StringFilterGroup(
Settings.ADVANCED_VIDEO_QUALITY_MENU, Settings.ADVANCED_VIDEO_QUALITY_MENU,
"quick_quality_sheet_content.eml-js" "quick_quality_sheet_content.e"
)); ));
} }

View File

@@ -4,13 +4,13 @@ import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
final class ButtonsFilter extends Filter { final class ButtonsFilter extends Filter {
private static final String COMPACT_CHANNEL_BAR_PATH_PREFIX = "compact_channel_bar.eml"; private static final String COMPACT_CHANNEL_BAR_PATH_PREFIX = "compact_channel_bar.e";
private static final String VIDEO_ACTION_BAR_PATH_PREFIX = "video_action_bar.eml"; private static final String VIDEO_ACTION_BAR_PATH_PREFIX = "video_action_bar.e";
private static final String VIDEO_ACTION_BAR_PATH = "video_action_bar.eml"; private static final String VIDEO_ACTION_BAR_PATH = "video_action_bar.e";
/** /**
* Video bar path when the video information is collapsed. Seems to shown only with 20.14+ * Video bar path when the video information is collapsed. Seems to shown only with 20.14+
*/ */
private static final String COMPACTIFY_VIDEO_ACTION_BAR_PATH = "compactify_video_action_bar.eml"; private static final String COMPACTIFY_VIDEO_ACTION_BAR_PATH = "compactify_video_action_bar.e";
private static final String ANIMATED_VECTOR_TYPE_PATH = "AnimatedVectorType"; private static final String ANIMATED_VECTOR_TYPE_PATH = "AnimatedVectorType";
private final StringFilterGroup likeSubscribeGlow; private final StringFilterGroup likeSubscribeGlow;
@@ -28,12 +28,12 @@ final class ButtonsFilter extends Filter {
likeSubscribeGlow = new StringFilterGroup( likeSubscribeGlow = new StringFilterGroup(
Settings.DISABLE_LIKE_SUBSCRIBE_GLOW, Settings.DISABLE_LIKE_SUBSCRIBE_GLOW,
"animated_button_border.eml" "animated_button_border.e"
); );
bufferFilterPathGroup = new StringFilterGroup( bufferFilterPathGroup = new StringFilterGroup(
null, null,
"|ContainerType|button.eml" "|ContainerType|button.e"
); );
addPathCallbacks( addPathCallbacks(
@@ -45,7 +45,7 @@ final class ButtonsFilter extends Filter {
), ),
new StringFilterGroup( new StringFilterGroup(
Settings.HIDE_DOWNLOAD_BUTTON, Settings.HIDE_DOWNLOAD_BUTTON,
"|download_button.eml" "|download_button.e"
), ),
new StringFilterGroup( new StringFilterGroup(
Settings.HIDE_SAVE_BUTTON, Settings.HIDE_SAVE_BUTTON,
@@ -53,7 +53,7 @@ final class ButtonsFilter extends Filter {
), ),
new StringFilterGroup( new StringFilterGroup(
Settings.HIDE_CLIP_BUTTON, Settings.HIDE_CLIP_BUTTON,
"|clip_button.eml" "|clip_button.e"
) )
); );

View File

@@ -6,7 +6,7 @@ import app.revanced.extension.youtube.shared.PlayerType;
@SuppressWarnings("unused") @SuppressWarnings("unused")
final class CommentsFilter extends Filter { final class CommentsFilter extends Filter {
private static final String COMMENT_COMPOSER_PATH = "comment_composer.eml"; private static final String COMMENT_COMPOSER_PATH = "comment_composer.e";
private final StringFilterGroup chipBar; private final StringFilterGroup chipBar;
private final ByteArrayFilterGroup aiCommentsSummary; private final ByteArrayFilterGroup aiCommentsSummary;
@@ -15,12 +15,12 @@ final class CommentsFilter extends Filter {
public CommentsFilter() { public CommentsFilter() {
var chatSummary = new StringFilterGroup( var chatSummary = new StringFilterGroup(
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY, Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
"live_chat_summary_banner.eml" "live_chat_summary_banner.e"
); );
chipBar = new StringFilterGroup( chipBar = new StringFilterGroup(
Settings.HIDE_COMMENTS_AI_SUMMARY, Settings.HIDE_COMMENTS_AI_SUMMARY,
"chip_bar.eml" "chip_bar.e"
); );
aiCommentsSummary = new ByteArrayFilterGroup( aiCommentsSummary = new ByteArrayFilterGroup(
@@ -35,8 +35,8 @@ final class CommentsFilter extends Filter {
var commentsByMembers = new StringFilterGroup( var commentsByMembers = new StringFilterGroup(
Settings.HIDE_COMMENTS_BY_MEMBERS_HEADER, Settings.HIDE_COMMENTS_BY_MEMBERS_HEADER,
"sponsorships_comments_header.eml", "sponsorships_comments_header.e",
"sponsorships_comments_footer.eml" "sponsorships_comments_footer.e"
); );
var comments = new StringFilterGroup( var comments = new StringFilterGroup(
@@ -52,7 +52,7 @@ final class CommentsFilter extends Filter {
var createAShort = new StringFilterGroup( var createAShort = new StringFilterGroup(
Settings.HIDE_COMMENTS_CREATE_A_SHORT_BUTTON, Settings.HIDE_COMMENTS_CREATE_A_SHORT_BUTTON,
"composer_short_creation_button.eml" "composer_short_creation_button.e"
); );
emojiAndTimestampButtons = new StringFilterGroup( emojiAndTimestampButtons = new StringFilterGroup(
@@ -69,7 +69,7 @@ final class CommentsFilter extends Filter {
var thanksButton = new StringFilterGroup( var thanksButton = new StringFilterGroup(
Settings.HIDE_COMMENTS_THANKS_BUTTON, Settings.HIDE_COMMENTS_THANKS_BUTTON,
"super_thanks_button.eml" "super_thanks_button.e"
); );
addPathCallbacks( addPathCallbacks(

View File

@@ -29,12 +29,12 @@ final class DescriptionComponentsFilter extends Filter {
aiGeneratedVideoSummarySection = new StringFilterGroup( aiGeneratedVideoSummarySection = new StringFilterGroup(
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION, Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
"cell_expandable_metadata.eml" "cell_expandable_metadata.e"
); );
final StringFilterGroup askSection = new StringFilterGroup( final StringFilterGroup askSection = new StringFilterGroup(
Settings.HIDE_ASK_SECTION, Settings.HIDE_ASK_SECTION,
"youchat_entrypoint.eml" "youchat_entrypoint.e"
); );
final StringFilterGroup attributesSection = new StringFilterGroup( final StringFilterGroup attributesSection = new StringFilterGroup(
@@ -65,7 +65,7 @@ final class DescriptionComponentsFilter extends Filter {
macroMarkersCarousel = new StringFilterGroup( macroMarkersCarousel = new StringFilterGroup(
null, null,
"macro_markers_carousel.eml" "macro_markers_carousel.e"
); );
macroMarkersCarouselGroupList.addAll( macroMarkersCarouselGroupList.addAll(
@@ -81,7 +81,7 @@ final class DescriptionComponentsFilter extends Filter {
horizontalShelf = new StringFilterGroup( horizontalShelf = new StringFilterGroup(
Settings.HIDE_ATTRIBUTES_SECTION, Settings.HIDE_ATTRIBUTES_SECTION,
"horizontal_shelf.eml" "horizontal_shelf.e"
); );
cellVideoAttribute = new ByteArrayFilterGroup( cellVideoAttribute = new ByteArrayFilterGroup(

View File

@@ -9,7 +9,7 @@ public final class HideInfoCardsFilter extends Filter {
addIdentifierCallbacks( addIdentifierCallbacks(
new StringFilterGroup( new StringFilterGroup(
Settings.HIDE_INFO_CARDS, Settings.HIDE_INFO_CARDS,
"info_card_teaser_overlay.eml" "info_card_teaser_overlay.e"
) )
); );
} }

View File

@@ -79,10 +79,10 @@ final class KeywordContentFilter extends Filter {
"search_vwc_description_transition_key", "search_vwc_description_transition_key",
"g-high-recZ", "g-high-recZ",
// Text and litho components found in the buffer that belong to path filters. // Text and litho components found in the buffer that belong to path filters.
"expandable_metadata.eml", "expandable_metadata.e",
"thumbnail.eml", "thumbnail.e",
"avatar.eml", "avatar.e",
"overflow_button.eml", "overflow_button.e",
"shorts-lockup-image", "shorts-lockup-image",
"shorts-lockup.overlay-metadata.secondary-text", "shorts-lockup.overlay-metadata.secondary-text",
"YouTubeSans-SemiBold", "YouTubeSans-SemiBold",
@@ -94,16 +94,16 @@ final class KeywordContentFilter extends Filter {
*/ */
private final StringFilterGroup startsWithFilter = new StringFilterGroup( private final StringFilterGroup startsWithFilter = new StringFilterGroup(
null, // Multiple settings are used and must be individually checked if active. null, // Multiple settings are used and must be individually checked if active.
"home_video_with_context.eml", "home_video_with_context.e",
"search_video_with_context.eml", "search_video_with_context.e",
"video_with_context.eml", // Subscription tab videos. "video_with_context.e", // Subscription tab videos.
"related_video_with_context.eml", "related_video_with_context.e",
// A/B test for subscribed video, and sometimes when tablet layout is enabled. // A/B test for subscribed video, and sometimes when tablet layout is enabled.
"video_lockup_with_attachment.eml", "video_lockup_with_attachment.e",
"compact_video.eml", "compact_video.e",
"inline_shorts", "inline_shorts",
"shorts_video_cell", "shorts_video_cell",
"shorts_pivot_item.eml" "shorts_pivot_item.e"
); );
/** /**
@@ -112,9 +112,9 @@ final class KeywordContentFilter extends Filter {
@SuppressWarnings("FieldCanBeLocal") @SuppressWarnings("FieldCanBeLocal")
private final StringFilterGroup containsFilter = new StringFilterGroup( private final StringFilterGroup containsFilter = new StringFilterGroup(
null, null,
"modern_type_shelf_header_content.eml", "modern_type_shelf_header_content.e",
"shorts_lockup_cell.eml", // Part of 'shorts_shelf_carousel.eml' "shorts_lockup_cell.e", // Part of 'shorts_shelf_carousel.e'
"video_card.eml" // Shorts that appear in a horizontal shelf. "video_card.e" // Shorts that appear in a horizontal shelf.
); );
/** /**
@@ -125,10 +125,10 @@ final class KeywordContentFilter extends Filter {
* the buffer of the parent component was already searched and passed. * the buffer of the parent component was already searched and passed.
*/ */
private final StringTrieSearch exceptions = new StringTrieSearch( private final StringTrieSearch exceptions = new StringTrieSearch(
"metadata.eml", "metadata.e",
"thumbnail.eml", "thumbnail.e",
"avatar.eml", "avatar.e",
"overflow_button.eml" "overflow_button.e"
); );
/** /**

View File

@@ -76,18 +76,18 @@ public final class LayoutComponentsFilter extends Filter {
communityPosts = new StringFilterGroup( communityPosts = new StringFilterGroup(
Settings.HIDE_COMMUNITY_POSTS, Settings.HIDE_COMMUNITY_POSTS,
"post_base_wrapper", // may be obsolete and no longer needed. "post_base_wrapper", // may be obsolete and no longer needed.
"text_post_root.eml", "text_post_root.e",
"images_post_root.eml", "images_post_root.e",
"images_post_slim.eml", // may be obsolete and no longer needed. "images_post_slim.e", // may be obsolete and no longer needed.
"images_post_root_slim.eml", "images_post_root_slim.e",
"text_post_root_slim.eml", "text_post_root_slim.e",
"post_base_wrapper_slim.eml", "post_base_wrapper_slim.e",
"poll_post_root.eml", "poll_post_root.e",
"videos_post_root.eml", "videos_post_root.e",
"post_shelf_slim.eml", "post_shelf_slim.e",
"videos_post_responsive_root.eml", "videos_post_responsive_root.e",
"text_post_responsive_root.eml", "text_post_responsive_root.e",
"poll_post_responsive_root.eml" "poll_post_responsive_root.e"
); );
final var subscribersCommunityGuidelines = new StringFilterGroup( final var subscribersCommunityGuidelines = new StringFilterGroup(
@@ -149,7 +149,7 @@ public final class LayoutComponentsFilter extends Filter {
final var channelLinksPreview = new StringFilterGroup( final var channelLinksPreview = new StringFilterGroup(
Settings.HIDE_LINKS_PREVIEW, Settings.HIDE_LINKS_PREVIEW,
"attribution.eml" "attribution.e"
); );
final var emergencyBox = new StringFilterGroup( final var emergencyBox = new StringFilterGroup(
@@ -190,8 +190,8 @@ public final class LayoutComponentsFilter extends Filter {
final var playables = new StringFilterGroup( final var playables = new StringFilterGroup(
Settings.HIDE_PLAYABLES, Settings.HIDE_PLAYABLES,
"horizontal_gaming_shelf.eml", "horizontal_gaming_shelf.e",
"mini_game_card.eml" "mini_game_card.e"
); );
// Playable horizontal shelf header. // Playable horizontal shelf header.
@@ -228,7 +228,7 @@ public final class LayoutComponentsFilter extends Filter {
compactChannelBarInnerButton = new StringFilterGroup( compactChannelBarInnerButton = new StringFilterGroup(
null, null,
"|button.eml" "|button.e"
); );
joinMembershipButton = new ByteArrayFilterGroup( joinMembershipButton = new ByteArrayFilterGroup(
@@ -248,13 +248,13 @@ public final class LayoutComponentsFilter extends Filter {
final var videoRecommendationLabels = new StringFilterGroup( final var videoRecommendationLabels = new StringFilterGroup(
Settings.HIDE_VIDEO_RECOMMENDATION_LABELS, Settings.HIDE_VIDEO_RECOMMENDATION_LABELS,
"endorsement_header_footer.eml" "endorsement_header_footer.e"
); );
channelProfile = new StringFilterGroup( channelProfile = new StringFilterGroup(
null, null,
"channel_profile.eml", "channel_profile.e",
"page_header.eml" "page_header.e"
); );
channelProfileBuffer = new ByteArrayFilterGroupList(); channelProfileBuffer = new ByteArrayFilterGroupList();
channelProfileBuffer.addAll(new ByteArrayFilterGroup( channelProfileBuffer.addAll(new ByteArrayFilterGroup(
@@ -269,15 +269,15 @@ public final class LayoutComponentsFilter extends Filter {
horizontalShelves = new StringFilterGroup( horizontalShelves = new StringFilterGroup(
Settings.HIDE_HORIZONTAL_SHELVES, Settings.HIDE_HORIZONTAL_SHELVES,
"horizontal_video_shelf.eml", "horizontal_video_shelf.e",
"horizontal_shelf.eml", "horizontal_shelf.e",
"horizontal_shelf_inline.eml", "horizontal_shelf_inline.e",
"horizontal_tile_shelf.eml" "horizontal_tile_shelf.e"
); );
ticketShelf = new ByteArrayFilterGroup( ticketShelf = new ByteArrayFilterGroup(
Settings.HIDE_TICKET_SHELF, Settings.HIDE_TICKET_SHELF,
"ticket_item.eml" "ticket_item.e"
); );
addPathCallbacks( addPathCallbacks(

View File

@@ -24,13 +24,13 @@ public final class PlaybackSpeedMenuFilter extends Filter {
// 0.05x litho speed menu. // 0.05x litho speed menu.
var playbackRateSelectorGroup = new StringFilterGroup( var playbackRateSelectorGroup = new StringFilterGroup(
Settings.CUSTOM_SPEED_MENU, Settings.CUSTOM_SPEED_MENU,
"playback_rate_selector_menu_sheet.eml-js" "playback_rate_selector_menu_sheet.e"
); );
// Old litho based speed menu. // Old litho based speed menu.
oldPlaybackMenuGroup = new StringFilterGroup( oldPlaybackMenuGroup = new StringFilterGroup(
Settings.CUSTOM_SPEED_MENU, Settings.CUSTOM_SPEED_MENU,
"playback_speed_sheet_content.eml-js"); "playback_speed_sheet_content.e");
addPathCallbacks(playbackRateSelectorGroup, oldPlaybackMenuGroup); addPathCallbacks(playbackRateSelectorGroup, oldPlaybackMenuGroup);
} }

View File

@@ -38,7 +38,7 @@ public class PlayerFlyoutMenuItemsFilter extends Filter {
addPathCallbacks( addPathCallbacks(
videoQualityMenuFooter, videoQualityMenuFooter,
new StringFilterGroup(null, "overflow_menu_item.eml") new StringFilterGroup(null, "overflow_menu_item.e")
); );
flyoutFilterGroupList.addAll( flyoutFilterGroupList.addAll(

View File

@@ -72,8 +72,8 @@ public final class ReturnYouTubeDislikeFilter extends Filter {
// But if swiping back to a previous video and liking/disliking, then only that single button reloads. // But if swiping back to a previous video and liking/disliking, then only that single button reloads.
// So must check for both buttons. // So must check for both buttons.
addPathCallbacks( addPathCallbacks(
new StringFilterGroup(null, "|shorts_like_button.eml"), new StringFilterGroup(null, "|shorts_like_button.e"),
new StringFilterGroup(null, "|shorts_dislike_button.eml") new StringFilterGroup(null, "|shorts_dislike_button.e")
); );
// After the button identifiers is binary data and then the video id for that specific short. // After the button identifiers is binary data and then the video id for that specific short.

View File

@@ -18,12 +18,12 @@ import app.revanced.extension.youtube.shared.PlayerType;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class ShortsFilter extends Filter { public final class ShortsFilter extends Filter {
private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get(); private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get();
private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.eml"; private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.e";
/** /**
* For paid promotion label and subscribe button that appears in the channel bar. * For paid promotion label and subscribe button that appears in the channel bar.
*/ */
private static final String REEL_METAPANEL_PATH = "reel_metapanel.eml"; private static final String REEL_METAPANEL_PATH = "reel_metapanel.e";
/** /**
* Tags that appears when opening the Shorts player. * Tags that appears when opening the Shorts player.
@@ -74,7 +74,7 @@ public final class ShortsFilter extends Filter {
// Use a different filter group for this pattern, as it requires an additional check after matching. // Use a different filter group for this pattern, as it requires an additional check after matching.
shelfHeader = new StringFilterGroup( shelfHeader = new StringFilterGroup(
null, null,
"shelf_header.eml" "shelf_header.e"
); );
addIdentifierCallbacks(shortsIdentifiers, shelfHeader); addIdentifierCallbacks(shortsIdentifiers, shelfHeader);
@@ -85,11 +85,11 @@ public final class ShortsFilter extends Filter {
shortsCompactFeedVideo = new StringFilterGroup(null, shortsCompactFeedVideo = new StringFilterGroup(null,
// Shorts that appear in the feed/search when the device is using tablet layout. // Shorts that appear in the feed/search when the device is using tablet layout.
"compact_video.eml", "compact_video.e",
// 'video_lockup_with_attachment.eml' is shown instead of 'compact_video.eml' for some users // 'video_lockup_with_attachment.e' is shown instead of 'compact_video.e' for some users
"video_lockup_with_attachment.eml", "video_lockup_with_attachment.e",
// Search results that appear in a horizontal shelf. // Search results that appear in a horizontal shelf.
"video_card.eml"); "video_card.e");
// Filter out items that use the 'frame0' thumbnail. // Filter out items that use the 'frame0' thumbnail.
// This is a valid thumbnail for both regular videos and Shorts, // This is a valid thumbnail for both regular videos and Shorts,
@@ -134,31 +134,31 @@ public final class ShortsFilter extends Filter {
StringFilterGroup stickers = new StringFilterGroup( StringFilterGroup stickers = new StringFilterGroup(
Settings.HIDE_SHORTS_STICKERS, Settings.HIDE_SHORTS_STICKERS,
"stickers_layer.eml" "stickers_layer.e"
); );
StringFilterGroup likeFountain = new StringFilterGroup( StringFilterGroup likeFountain = new StringFilterGroup(
Settings.HIDE_SHORTS_LIKE_FOUNTAIN, Settings.HIDE_SHORTS_LIKE_FOUNTAIN,
"like_fountain.eml" "like_fountain.e"
); );
StringFilterGroup likeButton = new StringFilterGroup( StringFilterGroup likeButton = new StringFilterGroup(
Settings.HIDE_SHORTS_LIKE_BUTTON, Settings.HIDE_SHORTS_LIKE_BUTTON,
"shorts_like_button.eml", "shorts_like_button.e",
"reel_like_button.eml" "reel_like_button.e"
); );
StringFilterGroup dislikeButton = new StringFilterGroup( StringFilterGroup dislikeButton = new StringFilterGroup(
Settings.HIDE_SHORTS_DISLIKE_BUTTON, Settings.HIDE_SHORTS_DISLIKE_BUTTON,
"shorts_dislike_button.eml", "shorts_dislike_button.e",
"reel_dislike_button.eml" "reel_dislike_button.e"
); );
StringFilterGroup previewComment = new StringFilterGroup( StringFilterGroup previewComment = new StringFilterGroup(
Settings.HIDE_SHORTS_PREVIEW_COMMENT, Settings.HIDE_SHORTS_PREVIEW_COMMENT,
// Preview comment that can popup while a Short is playing. // Preview comment that can popup while a Short is playing.
// Uses no bundled icons, and instead the users profile photo is shown. // Uses no bundled icons, and instead the users profile photo is shown.
"participation_bar.eml" "participation_bar.e"
); );
joinButton = new StringFilterGroup( joinButton = new StringFilterGroup(
@@ -173,20 +173,20 @@ public final class ShortsFilter extends Filter {
paidPromotionButton = new StringFilterGroup( paidPromotionButton = new StringFilterGroup(
Settings.HIDE_PAID_PROMOTION_LABEL, Settings.HIDE_PAID_PROMOTION_LABEL,
"reel_player_disclosure.eml" "reel_player_disclosure.e"
); );
shortsActionBar = new StringFilterGroup( shortsActionBar = new StringFilterGroup(
null, null,
"shorts_action_bar.eml", "shorts_action_bar.e",
"reel_action_bar.eml" "reel_action_bar.e"
); );
useSoundButton = new StringFilterGroup( useSoundButton = new StringFilterGroup(
Settings.HIDE_SHORTS_USE_SOUND_BUTTON, Settings.HIDE_SHORTS_USE_SOUND_BUTTON,
// First filter needed for "Use this sound" that can appear when viewing Shorts // First filter needed for "Use this sound" that can appear when viewing Shorts
// through the "Short remixing this video" section. // through the "Short remixing this video" section.
"floating_action_button.eml", "floating_action_button.e",
// Second filter needed for "Use this sound" that can appear below the video title. // Second filter needed for "Use this sound" that can appear below the video title.
REEL_METAPANEL_PATH REEL_METAPANEL_PATH
); );
@@ -209,13 +209,13 @@ public final class ShortsFilter extends Filter {
videoActionButton = new StringFilterGroup( videoActionButton = new StringFilterGroup(
null, null,
// Can be simply 'button.eml', 'shorts_video_action_button.eml' or 'reel_action_button.eml' // Can be simply 'button.e', 'shorts_video_action_button.e' or 'reel_action_button.e'
"button.eml" "button.e"
); );
suggestedAction = new StringFilterGroup( suggestedAction = new StringFilterGroup(
null, null,
"suggested_action.eml" "suggested_action.e"
); );
addPathCallbacks( addPathCallbacks(

View File

@@ -8,38 +8,40 @@ import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
import java.util.List; import java.util.List;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class SpoofVideoStreamsPatch { public class SpoofVideoStreamsPatch {
public static final class SpoofClientAv1Availability implements Setting.Availability {
@Override
public boolean isAvailable() {
return Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.isAvailable()
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ANDROID_VR_1_43_32;
}
}
/** /**
* Injection point. * Injection point.
*/ */
public static void setClientOrderToUse() { public static void setClientOrderToUse() {
final boolean forceAVC = Settings.FORCE_AVC_CODEC.get();
// VR 1.61 uses VP9/AV1, and cannot force AVC.
ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
if (forceAVC && client == ANDROID_VR_1_61_48) {
client = ANDROID_VR_1_43_32; // Use VR 1.43 instead. // Use VR 1.61 client that has AV1 if user settings allow it.
// AVC cannot be forced with VR 1.61 because it uses VP9 and AV1.
// If both settings are on, then force AVC takes priority and VR 1.43 is used.
if (client == ANDROID_VR_1_43_32 && Settings.SPOOF_VIDEO_STREAMS_AV1.get()
&& !Settings.FORCE_AVC_CODEC.get()) {
client = ANDROID_VR_1_61_48;
} }
List<ClientType> availableClients = forceAVC List<ClientType> availableClients = List.of(
? List.of(
ANDROID_VR_1_43_32,
VISIONOS,
ANDROID_CREATOR,
ANDROID_VR_1_61_48,
IPADOS)
: List.of(
ANDROID_VR_1_61_48,
VISIONOS,
ANDROID_CREATOR, ANDROID_CREATOR,
ANDROID_VR_1_43_32, ANDROID_VR_1_43_32,
IPADOS VISIONOS,
); IPADOS);
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse( app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
availableClients, client); availableClients, client);

View File

@@ -21,6 +21,7 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerT
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType; import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability; import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability; import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
import static app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch.SpoofClientAv1Availability;
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle; import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration; import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE; import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
@@ -55,6 +56,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE); public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE); public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message"); public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message");
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2); public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE); public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
@@ -75,9 +77,6 @@ public class Settings extends BaseSettings {
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds", public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true); "0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);
// Audio
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
// Ads // Ads
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE); public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true); public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true);
@@ -358,7 +357,9 @@ public class Settings extends BaseSettings {
public static final BooleanSetting EXTERNAL_BROWSER = new BooleanSetting("revanced_external_browser", TRUE, true); public static final BooleanSetting EXTERNAL_BROWSER = new BooleanSetting("revanced_external_browser", TRUE, true);
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true, public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
"revanced_spoof_device_dimensions_user_dialog_message"); "revanced_spoof_device_dimensions_user_dialog_message");
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS)); public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting SPOOF_VIDEO_STREAMS_AV1 = new BooleanSetting("revanced_spoof_video_streams_av1", FALSE, true,
"revanced_spoof_video_streams_av1_user_dialog_message", new SpoofClientAv1Availability());
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false, public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG)); "revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
@@ -526,6 +527,11 @@ public class Settings extends BaseSettings {
SPOOF_APP_VERSION.resetToDefault(); SPOOF_APP_VERSION.resetToDefault();
} }
// VR 1.61 is not selectable in the settings, and it's selected by spoof stream patch if needed.
if (SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_1_61_48) {
SPOOF_VIDEO_STREAMS_CLIENT_TYPE.resetToDefault();
}
// RYD requires manually migrating old settings since the lack of // RYD requires manually migrating old settings since the lack of
// a "revanced_" on the old setting causes duplicate key exceptions during export. // a "revanced_" on the old setting causes duplicate key exceptions during export.
SharedPrefCategory revancedPrefs = Setting.preferences; SharedPrefCategory revancedPrefs = Setting.preferences;

View File

@@ -83,12 +83,13 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
String summary = str("revanced_spoof_video_streams_about_no_audio_tracks"); String summary = str("revanced_spoof_video_streams_about_no_audio_tracks");
switch (clientType) { switch (clientType) {
case ANDROID_VR_1_61_48 ->
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
case ANDROID_CREATOR -> case ANDROID_CREATOR ->
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1") summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume") + '\n' + str("revanced_spoof_video_streams_about_no_av1")
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio"); + '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
// VR 1.61 is not exposed in the UI and should never be reached here.
case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 ->
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
case IPADOS -> case IPADOS ->
summary = str("revanced_spoof_video_streams_about_playback_failure") summary = str("revanced_spoof_video_streams_about_playback_failure")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1"); + '\n' + str("revanced_spoof_video_streams_about_no_av1");

View File

@@ -4,8 +4,10 @@ import android.app.Dialog;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.widget.Toolbar; import android.widget.Toolbar;
import app.revanced.extension.shared.GmsCoreSupport;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment; import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
import app.revanced.extension.youtube.settings.YouTubeActivityHook; import app.revanced.extension.youtube.settings.YouTubeActivityHook;
@@ -30,6 +32,17 @@ public class YouTubePreferenceFragment extends ToolbarPreferenceFragment {
preferenceScreen = getPreferenceScreen(); preferenceScreen = getPreferenceScreen();
Utils.sortPreferenceGroups(preferenceScreen); Utils.sortPreferenceGroups(preferenceScreen);
setPreferenceScreenToolbar(preferenceScreen); setPreferenceScreenToolbar(preferenceScreen);
// Clunky work around until preferences are custom classes that manage themselves.
// Custom branding only works with non-root install. But the preferences must be
// added during patched because of difficulties detecting during patching if it's
// a root install. So instead the non-functional preferences are removed during
// runtime if the app is mount (root) installation.
if (GmsCoreSupport.isPackageNameOriginal()) {
removePreferences(
BaseSettings.CUSTOM_BRANDING_ICON.key,
BaseSettings.CUSTOM_BRANDING_NAME.key);
}
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex); Logger.printException(() -> "initialize failure", ex);
} }

View File

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

View File

@@ -10,7 +10,7 @@ annotation = "1.9.1"
appcompat = "1.7.0" appcompat = "1.7.0"
okhttp = "5.0.0-alpha.14" okhttp = "5.0.0-alpha.14"
retrofit = "2.11.0" retrofit = "2.11.0"
guava = "33.4.0-jre" guava = "33.5.0-jre"
protobuf-javalite = "4.32.0" protobuf-javalite = "4.32.0"
protoc = "4.32.0" protoc = "4.32.0"
protobuf = "0.9.5" protobuf = "0.9.5"

42
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.10.1", "gradle-semantic-release-plugin": "^1.10.1",
"semantic-release": "^24.2.7" "semantic-release": "^24.2.9"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@@ -6889,9 +6889,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/semantic-release": { "node_modules/semantic-release": {
"version": "24.2.7", "version": "24.2.9",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.7.tgz", "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz",
"integrity": "sha512-g7RssbTAbir1k/S7uSwSVZFfFXwpomUB9Oas0+xi9KStSCmeDXcA7rNhiskjLqvUe/Evhx8fVCT16OSa34eM5g==", "integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -6909,7 +6909,7 @@
"find-versions": "^6.0.0", "find-versions": "^6.0.0",
"get-stream": "^6.0.0", "get-stream": "^6.0.0",
"git-log-parser": "^1.2.0", "git-log-parser": "^1.2.0",
"hook-std": "^3.0.0", "hook-std": "^4.0.0",
"hosted-git-info": "^8.0.0", "hosted-git-info": "^8.0.0",
"import-from-esm": "^2.0.0", "import-from-esm": "^2.0.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
@@ -6921,7 +6921,7 @@
"read-package-up": "^11.0.0", "read-package-up": "^11.0.0",
"resolve-from": "^5.0.0", "resolve-from": "^5.0.0",
"semver": "^7.3.2", "semver": "^7.3.2",
"semver-diff": "^4.0.0", "semver-diff": "^5.0.0",
"signale": "^1.2.1", "signale": "^1.2.1",
"yargs": "^17.5.1" "yargs": "^17.5.1"
}, },
@@ -7045,6 +7045,19 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/semantic-release/node_modules/hook-std": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-4.0.0.tgz",
"integrity": "sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/human-signals": { "node_modules/semantic-release/node_modules/human-signals": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
@@ -7138,6 +7151,23 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/semantic-release/node_modules/semver-diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-5.0.0.tgz",
"integrity": "sha512-0HbGtOm+S7T6NGQ/pxJSJipJvc4DK3FcRVMRkhsIwJDJ4Jcz5DQC1cPPzB5GhzyHjwttW878HaWQq46CkL3cqg==",
"deprecated": "Deprecated as the semver package now supports this built-in.",
"dev": true,
"license": "MIT",
"dependencies": {
"semver": "^7.3.5"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/signal-exit": { "node_modules/semantic-release/node_modules/signal-exit": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",

View File

@@ -4,6 +4,6 @@
"@semantic-release/changelog": "^6.0.3", "@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1", "@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.10.1", "gradle-semantic-release-plugin": "^1.10.1",
"semantic-release": "^24.2.7" "semantic-release": "^24.2.9"
} }
} }

View File

@@ -269,7 +269,7 @@ public final class app/revanced/patches/instagram/feed/LimitFeedToFollowedProfil
} }
public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt { public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt {
public static final fun getHideExportFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideExploreFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt { public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt {
@@ -280,10 +280,30 @@ public final class app/revanced/patches/instagram/hide/stories/HideStoriesKt {
public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/instagram/hide/suggestions/HideSuggestedContentKt {
public static final fun getHideSuggestedContent ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatchKt {
public static final fun getEnableDeveloperMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/extension/SharedExtensionPatchKt { public final class app/revanced/patches/instagram/misc/extension/SharedExtensionPatchKt {
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/instagram/misc/links/OpenLinksExternallyPatchKt {
public static final fun getOpenLinksExternallyPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/share/domain/ChangeLinkSharingDomainPatchKt {
public static final fun getChangeLinkSharingDomainPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/share/privacy/SanitizeSharingLinksPatchKt {
public static final fun getSanitizeSharingLinksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt { public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -372,6 +392,10 @@ public final class app/revanced/patches/music/interaction/permanentshuffle/Perma
public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/music/layout/branding/CustomBrandingPatchKt {
public static final fun getCustomBrandingPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
}
public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt { public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt {
public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -451,9 +475,14 @@ public final class app/revanced/patches/music/misc/spoof/UserAgentClientSpoofPat
public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatchKt {
public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt { public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch; public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
public static final fun is_7_33_or_greater ()Z public static final fun is_7_33_or_greater ()Z
public static final fun is_8_10_or_greater ()Z
public static final fun is_8_11_or_greater ()Z public static final fun is_8_11_or_greater ()Z
public static final fun is_8_15_or_greater ()Z public static final fun is_8_15_or_greater ()Z
} }
@@ -997,11 +1026,6 @@ public final class app/revanced/patches/shared/misc/settings/preference/TextPref
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
} }
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;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 { public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatchKt {
public static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch; public static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -1411,8 +1435,8 @@ public final class app/revanced/patches/youtube/layout/formfactor/ChangeFormFact
public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatchKt { public final class app/revanced/patches/youtube/layout/hide/endscreencards/HideEndScreenCardsPatchKt {
public static final fun getHideEndscreenCardsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideEndScreenCardsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatchKt { public final class app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatchKt {
@@ -1899,6 +1923,7 @@ public final class app/revanced/util/ResourceUtilsKt {
public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V
public static final fun insertFirst (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)V public static final fun insertFirst (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)V
public static final fun iterateXmlNodeChildren (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V public static final fun iterateXmlNodeChildren (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public static final fun removeFromParent (Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
} }
public final class app/revanced/util/resource/ArrayResource : app/revanced/util/resource/BaseResource { public final class app/revanced/util/resource/ArrayResource : app/revanced/util/resource/BaseResource {

View File

@@ -2,11 +2,13 @@ package app.revanced.patches.finanzonline.detection.root
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
@Suppress("unused") @Suppress("unused")
val rootDetectionPatch = bytecodePatch( val rootDetectionPatch = bytecodePatch(
name = "Remove root detection", name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = "Removes the check for root permissions.", description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION,
) { ) {
compatibleWith("at.gv.bmf.bmf2go") compatibleWith("at.gv.bmf.bmf2go")

View File

@@ -1,12 +1,14 @@
package app.revanced.patches.idaustria.detection.root package app.revanced.patches.idaustria.detection.root
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
@Suppress("unused") @Suppress("unused")
val rootDetectionPatch = bytecodePatch( val rootDetectionPatch = bytecodePatch(
name = "Remove root detection", name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = "Removes the check for root permissions and unlocked bootloader.", description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
) { ) {
compatibleWith("at.gv.oe.app") compatibleWith("at.gv.oe.app")

View File

@@ -3,7 +3,9 @@ package app.revanced.patches.instagram.hide.explore
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
internal const val EXPLORE_KEY_TO_BE_HIDDEN = "sectional_items"
internal val exploreResponseJsonParserFingerprint = fingerprint { internal val exploreResponseJsonParserFingerprint = fingerprint {
strings("sectional_items", "ExploreTopicalFeedResponse") strings(EXPLORE_KEY_TO_BE_HIDDEN, "ExploreTopicalFeedResponse")
custom { method, _ -> method.name == "parseFromJson" } custom { method, _ -> method.name == "parseFromJson" }
} }

View File

@@ -1,33 +1,39 @@
package app.revanced.patches.instagram.hide.explore package app.revanced.patches.instagram.hide.explore
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
context(BytecodePatchContext)
internal fun Fingerprint.replaceJsonFieldWithBogus(
key: String,
) {
val targetStringIndex = stringMatches!!.first { match -> match.string == key }.index
val targetStringRegister = method.getInstruction<OneRegisterInstruction>(targetStringIndex).registerA
/**
* Replacing the JSON key we want to skip with a random string that is not a valid JSON key.
* This way the feeds array will never be populated.
* Received JSON keys that are not handled are simply ignored, so there are no side effects.
*/
method.replaceInstruction(
targetStringIndex,
"const-string v$targetStringRegister, \"BOGUS\"",
)
}
@Suppress("unused") @Suppress("unused")
val hideExportFeedPatch = bytecodePatch( val hideExploreFeedPatch = bytecodePatch(
name = "Hide explore feed", name = "Hide explore feed",
description = "Hides posts and reels from the explore/search page.", description = "Hides posts and reels from the explore/search page.",
use = false use = false,
) { ) {
compatibleWith("com.instagram.android") compatibleWith("com.instagram.android")
execute { execute {
exploreResponseJsonParserFingerprint.method.apply { exploreResponseJsonParserFingerprint.replaceJsonFieldWithBogus(EXPLORE_KEY_TO_BE_HIDDEN)
val sectionalItemStringIndex = exploreResponseJsonParserFingerprint.stringMatches!!.first().index
val sectionalItemStringRegister = getInstruction<OneRegisterInstruction>(sectionalItemStringIndex).registerA
/**
* Replacing the JSON key we want to skip with a random string that is not a valid JSON key.
* This way the feeds array will never be populated.
* Received JSON keys that are not handled are simply ignored, so there are no side effects.
*/
replaceInstruction(
sectionalItemStringIndex,
"const-string v$sectionalItemStringRegister, \"BOGUS\""
)
}
} }
} }

View File

@@ -0,0 +1,17 @@
package app.revanced.patches.instagram.hide.suggestions
import app.revanced.patcher.fingerprint
internal val FEED_ITEM_KEYS_TO_BE_HIDDEN = arrayOf(
"clips_netego",
"stories_netego",
"in_feed_survey",
"bloks_netego",
"suggested_igd_channels",
"suggested_top_accounts",
"suggested_users",
)
internal val feedItemParseFromJsonFingerprint = fingerprint {
strings(*FEED_ITEM_KEYS_TO_BE_HIDDEN, "FeedItem")
}

View File

@@ -0,0 +1,19 @@
package app.revanced.patches.instagram.hide.suggestions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.instagram.hide.explore.replaceJsonFieldWithBogus
@Suppress("unused")
val hideSuggestedContent = bytecodePatch(
name = "Hide suggested content",
description = "Hides suggested stories, reels, threads and survey from feed (Suggested posts will still be shown).",
use = false,
) {
compatibleWith("com.instagram.android")
execute {
FEED_ITEM_KEYS_TO_BE_HIDDEN.forEach { key ->
feedItemParseFromJsonFingerprint.replaceJsonFieldWithBogus(key)
}
}
}

View File

@@ -0,0 +1,37 @@
package app.revanced.patches.instagram.misc.devmenu
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
val enableDeveloperMenuPatch = bytecodePatch(
name = "Enable developer menu",
description = """
Enables the developer menu, which can be found at the bottom of settings menu with name 'Internal Settings'.
It is recommended to use this patch with an alpha/beta Instagram release. Patching a stable release works, but the developer menu shows the developer flags as numbers and does not show a human readable description.
""".trimIndentMultiline(),
use = false
) {
compatibleWith("com.instagram.android")
execute {
with(clearNotificationReceiverFingerprint.method) {
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) {
val reference = getReference<MethodReference>()
Opcode.INVOKE_STATIC == opcode &&
reference?.parameterTypes?.size == 1 &&
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
reference.returnType == "Z"
}.let { index ->
navigate(this).to(index).stop().returnEarly(true)
}
}
}
}

View File

@@ -0,0 +1,12 @@
package app.revanced.patches.instagram.misc.devmenu
import app.revanced.patcher.fingerprint
internal val clearNotificationReceiverFingerprint = fingerprint {
custom { method, classDef ->
method.name == "onReceive" &&
classDef.type == "Lcom/instagram/notifications/push/ClearNotificationReceiver;"
}
strings("NOTIFICATION_DISMISSED")
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.instagram.misc.links
import app.revanced.patcher.fingerprint
internal const val TARGET_STRING = "Tracking.ARG_CLICK_SOURCE"
internal val inAppBrowserFunctionFingerprint = fingerprint {
returns("Z")
strings("TrackingInfo.ARG_MODULE_NAME", TARGET_STRING)
}

View File

@@ -0,0 +1,47 @@
package app.revanced.patches.instagram.misc.links
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/instagram/misc/links/OpenLinksExternallyPatch;"
@Suppress("unused")
val openLinksExternallyPatch = bytecodePatch(
name = "Open links externally",
description = "Changes links to always open in your external browser, instead of the in-app browser.",
use = false,
) {
dependsOn(sharedExtensionPatch)
compatibleWith("com.instagram.android")
execute {
inAppBrowserFunctionFingerprint.let {
val stringMatchIndex = it.stringMatches?.first { match -> match.string == TARGET_STRING }!!.index
it.method.apply {
val urlResultObjIndex = indexOfFirstInstructionOrThrow(
stringMatchIndex, Opcode.MOVE_OBJECT_FROM16
)
// Register that contains the url after moving from a higher register.
val urlRegister = getInstruction<TwoRegisterInstruction>(urlResultObjIndex).registerA
addInstructions(
urlResultObjIndex + 1,
"""
invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->openExternally(Ljava/lang/String;)Z
move-result v$urlRegister
return v$urlRegister
"""
)
}
}
}
}

View File

@@ -0,0 +1,31 @@
package app.revanced.patches.instagram.misc.share
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
context(BytecodePatchContext)
internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int) -> Unit) {
val fingerprintsToPatch = arrayOf(
permalinkResponseJsonParserFingerprint,
storyUrlResponseJsonParserFingerprint,
profileUrlResponseJsonParserFingerprint,
liveUrlResponseJsonParserFingerprint
)
for (fingerprint in fingerprintsToPatch) {
fingerprint.method.apply {
val putSharingUrlIndex = indexOfFirstInstruction(
permalinkResponseJsonParserFingerprint.stringMatches!!.first().index,
Opcode.IPUT_OBJECT
)
val sharingUrlRegister = getInstruction<TwoRegisterInstruction>(putSharingUrlIndex).registerA
block(putSharingUrlIndex, sharingUrlRegister)
}
}
}

View File

@@ -0,0 +1,23 @@
package app.revanced.patches.instagram.misc.share
import app.revanced.patcher.fingerprint
internal val permalinkResponseJsonParserFingerprint = fingerprint {
strings("permalink", "PermalinkResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val storyUrlResponseJsonParserFingerprint = fingerprint {
strings("story_item_to_share_url", "StoryItemUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val profileUrlResponseJsonParserFingerprint = fingerprint {
strings("profile_to_share_url", "ProfileUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}
internal val liveUrlResponseJsonParserFingerprint = fingerprint {
strings("live_to_share_url", "LiveItemLinkUrlResponse")
custom { method, _ -> method.name == "parseFromJson" }
}

View File

@@ -0,0 +1,42 @@
package app.revanced.patches.instagram.misc.share.domain
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.patches.instagram.misc.share.editShareLinksPatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.util.returnEarly
@Suppress("unused")
val changeLinkSharingDomainPatch = bytecodePatch(
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN,
use = false
) {
compatibleWith("com.instagram.android")
dependsOn(sharedExtensionPatch)
val customDomainHost by stringOption(
key = "domainName",
default = "imginn.com",
title = "Domain name",
description = "The domain name to use when sharing links."
)
execute {
getCustomShareDomainFingerprint.method.returnEarly(customDomainHost!!)
editShareLinksPatch { index, register ->
addInstructions(
index,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setCustomShareDomain(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register
"""
)
}
}
}

View File

@@ -0,0 +1,16 @@
package app.revanced.patches.instagram.misc.share.domain
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/instagram/misc/share/domain/ChangeLinkSharingDomainPatch;"
internal val getCustomShareDomainFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { method, classDef ->
method.name == "getCustomShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}

View File

@@ -0,0 +1,33 @@
package app.revanced.patches.instagram.misc.share.privacy
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.patches.instagram.misc.share.editShareLinksPatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/instagram/misc/share/privacy/SanitizeSharingLinksPatch;"
@Suppress("unused")
val sanitizeSharingLinksPatch = bytecodePatch(
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
) {
compatibleWith("com.instagram.android")
dependsOn(sharedExtensionPatch)
execute {
editShareLinksPatch { index, register ->
addInstructions(
index,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register
"""
)
}
}
}

View File

@@ -0,0 +1,81 @@
package app.revanced.patches.music.layout.branding
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.Constants.MUSIC_MAIN_ACTIVITY_NAME
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.shared.layout.branding.baseCustomBrandingPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversed
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private val disableSplashAnimationPatch = bytecodePatch {
dependsOn(resourceMappingPatch)
execute {
// The existing YT animation usually only shows for a fraction of a second,
// and the existing animation does not match the new splash screen
// causing the original YT Music logo to momentarily flash on screen as the animation starts.
//
// Could replace the lottie animation file with our own custom animation (app_launch.json),
// but the animation is not always the same size as the launch screen and it's still
// barely shown. Instead turn off the animation entirely (app will also launch a little faster).
cairoSplashAnimationConfigFingerprint.method.apply {
val mainActivityLaunchAnimation = resourceMappings["layout", "main_activity_launch_animation"]
val literalIndex = indexOfFirstLiteralInstructionOrThrow(
mainActivityLaunchAnimation
)
val insertIndex = indexOfFirstInstructionReversed(literalIndex) {
this.opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setContentView"
} + 1
val jumpIndex = indexOfFirstInstructionOrThrow(insertIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.parameterTypes?.firstOrNull() == "Ljava/lang/Runnable;"
} + 1
addInstructionsWithLabels(
insertIndex,
"goto :skip_animation",
ExternalLabel("skip_animation", getInstruction(jumpIndex))
)
}
}
}
@Suppress("unused")
val customBrandingPatch = baseCustomBrandingPatch(
addResourcePatchName = "music",
originalLauncherIconName = "ic_launcher_release",
originalAppName = "@string/app_launcher_name",
originalAppPackageName = MUSIC_PACKAGE_NAME,
isYouTubeMusic = true,
numberOfPresetAppNames = 5,
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
mainActivityName = MUSIC_MAIN_ACTIVITY_NAME,
activityAliasNameWithIntents = MUSIC_MAIN_ACTIVITY_NAME,
preferenceScreen = PreferenceScreen.GENERAL,
block = {
dependsOn(sharedExtensionPatch, disableSplashAnimationPatch)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52",
"8.10.52"
)
)
}
)

View File

@@ -0,0 +1,12 @@
package app.revanced.patches.music.layout.branding
import app.revanced.patcher.fingerprint
import app.revanced.patches.music.shared.YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
internal val cairoSplashAnimationConfigFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && method.definingClass == YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
}
}

View File

@@ -0,0 +1,44 @@
package app.revanced.patches.music.misc.fileprovider
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.music.utils.fix.fileprovider.fileProviderResolverFingerprint
internal fun fileProviderPatch(
youtubePackageName: String,
musicPackageName: String
) = bytecodePatch(
description = "Fixes broken YouTube Music file provider that prevents sharing with specific apps such as Instagram."
) {
finalize {
// Must do modification last, so change package name value is correctly set.
val musicChangedPackageName = setOrGetFallbackPackageName(musicPackageName)
// For some reason, if the app gets "android.support.FILE_PROVIDER_PATHS",
// the package name of YouTube is used, not the package name of the YT Music.
//
// There is no issue in the stock YT Music, but this is an issue in the GmsCore Build.
// https://github.com/ReVanced/revanced-patches/issues/55
//
// To solve this issue, replace the package name of YouTube with YT Music's package name.
fileProviderResolverFingerprint.method.addInstructionsWithLabels(
0,
"""
const-string v0, "com.google.android.youtube.fileprovider"
invoke-static { p1, v0 }, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
move-result v0
if-nez v0, :fix
const-string v0, "$youtubePackageName.fileprovider"
invoke-static { p1, v0 }, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
move-result v0
if-nez v0, :fix
goto :ignore
:fix
const-string p1, "$musicChangedPackageName.fileprovider"
:ignore
nop
"""
)
}
}

View File

@@ -0,0 +1,11 @@
package app.revanced.patches.music.utils.fix.fileprovider
import app.revanced.patcher.fingerprint
internal val fileProviderResolverFingerprint = fingerprint {
returns("L")
strings(
"android.support.FILE_PROVIDER_PATHS",
"Name must not be empty"
)
}

View File

@@ -1,6 +1,8 @@
package app.revanced.patches.music.misc.gms package app.revanced.patches.music.misc.gms
object Constants { object Constants {
internal const val MUSIC_MAIN_ACTIVITY_NAME = "com.google.android.apps.youtube.music.activities.MusicActivity"
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music" internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music" internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music"
} }

View File

@@ -9,6 +9,7 @@ import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.settings.PreferenceScreen import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.music.misc.fileprovider.fileProviderPatch
import app.revanced.patches.shared.castContextFetchFingerprint import app.revanced.patches.shared.castContextFetchFingerprint
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.shared.misc.settings.preference.IntentPreference
@@ -60,6 +61,10 @@ private fun gmsCoreSupportResourcePatch(
) { ) {
dependsOn( dependsOn(
addResourcesPatch, addResourcesPatch,
settingsPatch settingsPatch,
fileProviderPatch(
MUSIC_PACKAGE_NAME,
REVANCED_MUSIC_PACKAGE_NAME
)
) )
} }

View File

@@ -6,6 +6,7 @@ import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
@@ -126,7 +127,7 @@ fun newIntent(settingsName: String) = IntentPreference.Intent(
targetClass = "com.google.android.gms.common.api.GoogleApiActivity" targetClass = "com.google.android.gms.common.api.GoogleApiActivity"
) { ) {
// The package name change has to be reflected in the intent. // The package name change has to be reflected in the intent.
setOrGetFallbackPackageName("com.google.android.apps.youtube.music") setOrGetFallbackPackageName(MUSIC_PACKAGE_NAME)
} }
object PreferenceScreen : BasePreferenceScreen() { object PreferenceScreen : BasePreferenceScreen() {

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.music.misc.spoof package app.revanced.patches.music.misc.spoof
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.extension.sharedExtensionPatch
@@ -16,12 +15,13 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPref
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
val spoofVideoStreamsPatch = spoofVideoStreamsPatch( val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
fixMediaFetchHotConfigChanges = { true }, extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater }, mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
fixMediaFetchHotConfig = { true },
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater }, fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
block = { block = {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,
@@ -38,6 +38,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
) )
) )
}, },
executeBlock = { executeBlock = {
addResources("music", "misc.fix.playback.spoofVideoStreamsPatch") addResources("music", "misc.fix.playback.spoofVideoStreamsPatch")
@@ -51,10 +52,5 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
) )
) )
) )
musicActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
)
} }
) )

View File

@@ -0,0 +1,34 @@
package app.revanced.patches.music.misc.tracks
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_8_10_or_greater
import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;"
@Suppress("unused")
val forceOriginalAudioPatch = forceOriginalAudioPatch(
block = {
dependsOn(
sharedExtensionPatch,
settingsPatch,
versionCheckPatch
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52",
"8.10.52"
)
)
},
fixUseLocalizedAudioTrackFlag = is_8_10_or_greater,
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
preferenceScreen = PreferenceScreen.MISC,
)

View File

@@ -7,6 +7,8 @@ import app.revanced.util.findPlayStoreServicesVersion
var is_7_33_or_greater = false var is_7_33_or_greater = false
private set private set
var is_8_10_or_greater = false
private set
var is_8_11_or_greater = false var is_8_11_or_greater = false
private set private set
var is_8_15_or_greater = false var is_8_15_or_greater = false
@@ -22,6 +24,7 @@ val versionCheckPatch = resourcePatch(
// All bug fix releases always seem to use the same play store version as the minor version. // All bug fix releases always seem to use the same play store version as the minor version.
is_7_33_or_greater = 245199000 <= playStoreServicesVersion is_7_33_or_greater = 245199000 <= playStoreServicesVersion
is_8_10_or_greater = 244799000 <= playStoreServicesVersion
is_8_11_or_greater = 251199000 <= playStoreServicesVersion is_8_11_or_greater = 251199000 <= playStoreServicesVersion
is_8_15_or_greater = 251530000 <= playStoreServicesVersion is_8_15_or_greater = 251530000 <= playStoreServicesVersion
} }

View File

@@ -1,12 +1,14 @@
package app.revanced.patches.orfon.detection.root package app.revanced.patches.orfon.detection.root
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
@Suppress("unused") @Suppress("unused")
val removeRootDetectionPatch = bytecodePatch( val removeRootDetectionPatch = bytecodePatch(
name = "Remove root detection", name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = "Removes the check for root permissions.", description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
) { ) {
compatibleWith("com.nousguide.android.orftvthek") compatibleWith("com.nousguide.android.orftvthek")

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.redgifs package app.revanced.patches.reddit.customclients.boostforreddit.fix.redgifs
import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.reddit.customclients.CREATE_NEW_CLIENT_METHOD import app.revanced.patches.reddit.customclients.CREATE_NEW_CLIENT_METHOD
import app.revanced.patches.reddit.customclients.boostforreddit.misc.extension.sharedExtensionPatch import app.revanced.patches.reddit.customclients.boostforreddit.misc.extension.sharedExtensionPatch
@@ -27,9 +26,7 @@ val fixRedgifsApi = fixRedgifsApiPatch(
} }
replaceInstruction( replaceInstruction(
index, index,
""" "invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->$CREATE_NEW_CLIENT_METHOD"
invoke-static { }, ${EXTENSION_CLASS_DESCRIPTOR}->$CREATE_NEW_CLIENT_METHOD
"""
) )
} }

View File

@@ -2,11 +2,13 @@ package app.revanced.patches.reddit.misc.tracking.url
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
@Suppress("unused") @Suppress("unused")
val sanitizeUrlQueryPatch = bytecodePatch( val sanitizeUrlQueryPatch = bytecodePatch(
name = "Sanitize sharing links", name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = "Removes (tracking) query parameters from the URLs when sharing links.", description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
) { ) {
compatibleWith("com.reddit.frontpage") compatibleWith("com.reddit.frontpage")

View File

@@ -2,11 +2,13 @@ package app.revanced.patches.serviceportalbund.detection.root
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
@Suppress("unused") @Suppress("unused")
val rootDetectionPatch = bytecodePatch( val rootDetectionPatch = bytecodePatch(
name = "Remove root detection", name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = "Removes the check for root permissions and unlocked bootloader.", description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
) { ) {
compatibleWith("at.gv.bka.serviceportal") compatibleWith("at.gv.bka.serviceportal")

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.shared
//
// Names and descriptions used by different patches implementing the same feature.
//
internal const val PATCH_NAME_REMOVE_ROOT_DETECTION = "Remove root detection"
internal const val PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION = "Removes the check for root permissions and unlocked bootloader."
internal const val PATCH_NAME_SANITIZE_SHARING_LINKS = "Sanitize sharing links"
internal const val PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS = "Removes the tracking query parameters from shared links."
internal const val PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN = "Change link sharing domain"
internal const val PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN = "Replaces the domain name of shared links."

View File

@@ -0,0 +1,461 @@
package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.ResourcePatchBuilder
import app.revanced.patcher.patch.ResourcePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.util.ResourceGroup
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.copyResources
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.removeFromParent
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import org.w3c.dom.Element
import org.w3c.dom.NodeList
import java.io.File
import java.util.logging.Logger
private val mipmapDirectories = arrayOf(
// Target app does not have ldpi icons.
"mipmap-mdpi",
"mipmap-hdpi",
"mipmap-xhdpi",
"mipmap-xxhdpi",
"mipmap-xxxhdpi"
)
private val iconStyleNames = arrayOf(
"rounded",
"minimal",
"scaled"
)
private const val ORIGINAL_USER_ICON_STYLE_NAME = "original"
private const val CUSTOM_USER_ICON_STYLE_NAME = "custom"
private const val LAUNCHER_RESOURCE_NAME_PREFIX = "revanced_launcher_"
private const val LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX = "revanced_adaptive_background_"
private const val LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX = "revanced_adaptive_foreground_"
private const val LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX = "revanced_adaptive_monochrome_"
private const val NOTIFICATION_ICON_NAME = "revanced_notification_icon"
private val USER_CUSTOM_ADAPTIVE_FILE_NAMES = arrayOf(
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png"
)
private const val USER_CUSTOM_MONOCHROME_FILE_NAME = "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
private const val USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME = "${NOTIFICATION_ICON_NAME}_$CUSTOM_USER_ICON_STYLE_NAME.xml"
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/patches/CustomBrandingPatch;"
/**
* Shared custom branding patch for YouTube and YT Music.
*/
internal fun baseCustomBrandingPatch(
addResourcePatchName: String,
originalLauncherIconName: String,
originalAppName: String,
originalAppPackageName: String,
isYouTubeMusic: Boolean,
numberOfPresetAppNames: Int,
mainActivityOnCreateFingerprint: Fingerprint,
mainActivityName: String,
activityAliasNameWithIntents: String,
preferenceScreen: BasePreferenceScreen.Screen,
block: ResourcePatchBuilder.() -> Unit,
executeBlock: ResourcePatchContext.() -> Unit = {}
): ResourcePatch = resourcePatch(
name = "Custom branding",
description = "Adds options to change the app icon and app name. " +
"Branding cannot be changed for mounted (root) installations."
) {
val customName by stringOption(
key = "customName",
title = "App name",
description = "Custom app name."
)
val customIcon by stringOption(
key = "customIcon",
title = "Custom icon",
description = """
Folder with images to use as a custom icon.
The folder must contain one or more of the following folders, depending on the DPI of the device:
${mipmapDirectories.joinToString("\n") { "- $it" }}
Each of the folders must contain all of the following files:
${USER_CUSTOM_ADAPTIVE_FILE_NAMES.joinToString("\n")}
Optionally, the path contains a 'drawable' folder with any of the monochrome icon files:
$USER_CUSTOM_MONOCHROME_FILE_NAME
$USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
""".trimIndentMultiline()
)
block()
dependsOn(
addResourcesPatch,
resourceMappingPatch,
bytecodePatch {
execute {
mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setBranding()V"
)
numberOfPresetAppNamesExtensionFingerprint.method.returnEarly(numberOfPresetAppNames)
notificationFingerprint.method.apply {
val getBuilderIndex = if (isYouTubeMusic) {
// YT Music the field is not a plain object type.
indexOfFirstInstructionOrThrow {
getReference<FieldReference>()?.type == "Landroid/app/Notification\$Builder;"
}
} else {
// Find the field name of the notification builder. Field is an Object type.
val builderCastIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<TypeReference>()
opcode == Opcode.CHECK_CAST &&
reference?.type == "Landroid/app/Notification\$Builder;"
}
indexOfFirstInstructionReversedOrThrow(builderCastIndex) {
getReference<FieldReference>()?.type == "Ljava/lang/Object;"
}
}
val builderFieldName = getInstruction<ReferenceInstruction>(getBuilderIndex)
.getReference<FieldReference>()
findInstructionIndicesReversedOrThrow(
Opcode.RETURN_VOID
).forEach { index ->
addInstructionsAtControlFlowLabel(
index,
"""
move-object/from16 v0, p0
iget-object v0, v0, $builderFieldName
check-cast v0, Landroid/app/Notification${'$'}Builder;
invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification${'$'}Builder;)V
"""
)
}
}
}
},
)
finalize {
// Can only check if app is root installation by checking if change package name patch is in use.
// and can only do that in the finalize block here.
// The UI preferences cannot be selectively added here, because the settings finalize block
// may have already run and the settings are already wrote to file.
// Instead, show a warning if any patch option was used (A rooted device launcher ignores the manifest changes),
// and the non-functional in-app settings are removed on app startup by extension code.
if (customName != null || customIcon != null) {
if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) {
Logger.getLogger(this::class.java.name).warning(
"Custom branding does not work with root installation. No changes applied."
)
}
}
}
execute {
addResources("shared", "layout.branding.baseCustomBrandingPatch")
addResources(addResourcePatchName, "layout.branding.customBrandingPatch")
preferenceScreen.addPreferences(
if (customName != null ) {
ListPreference(
key = "revanced_custom_branding_name",
entriesKey = "revanced_custom_branding_name_custom_entries",
entryValuesKey = "revanced_custom_branding_name_custom_entry_values"
)
} else {
ListPreference("revanced_custom_branding_name")
},
if (customIcon != null) {
ListPreference(
key = "revanced_custom_branding_icon",
entriesKey = "revanced_custom_branding_icon_custom_entries",
entryValuesKey = "revanced_custom_branding_icon_custom_entry_values"
)
} else {
ListPreference("revanced_custom_branding_icon")
}
)
val useCustomName = customName != null
val useCustomIcon = customIcon != null
iconStyleNames.forEach { style ->
copyResources(
"custom-branding",
ResourceGroup(
"drawable",
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$style.xml",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$style.xml",
"$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$style.xml",
),
ResourceGroup(
"mipmap-anydpi",
"$LAUNCHER_RESOURCE_NAME_PREFIX$style.xml"
)
)
}
copyResources(
"custom-branding",
// Push notification 'small' icon.
ResourceGroup(
"drawable",
"$NOTIFICATION_ICON_NAME.xml"
),
// Copy template user icon, because the aliases must be added even if no user icon is provided.
ResourceGroup(
"drawable",
USER_CUSTOM_MONOCHROME_FILE_NAME,
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
),
ResourceGroup(
"mipmap-anydpi",
"$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
)
)
// Copy template icon files.
mipmapDirectories.forEach { dpi ->
copyResources(
"custom-branding",
ResourceGroup(
dpi,
"$LAUNCHER_ADAPTIVE_BACKGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
"$LAUNCHER_ADAPTIVE_FOREGROUND_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.png",
)
)
}
document("AndroidManifest.xml").use { document ->
// Create launch aliases that can be programmatically selected in app.
fun createAlias(
aliasName: String,
iconMipmapName: String,
appNameIndex: Int,
useCustomName: Boolean,
enabled: Boolean,
intents: NodeList
): Element {
val label = if (useCustomName) {
if (customName == null) {
"Custom" // Dummy text, and normally cannot be seen.
} else {
customName!!
}
} else if (appNameIndex == 1) {
// Indexing starts at 1.
originalAppName
} else {
"@string/revanced_custom_branding_name_entry_$appNameIndex"
}
val alias = document.createElement("activity-alias")
alias.setAttribute("android:name", aliasName)
alias.setAttribute("android:enabled", enabled.toString())
alias.setAttribute("android:exported", "true")
alias.setAttribute("android:icon", "@mipmap/$iconMipmapName")
alias.setAttribute("android:label", label)
alias.setAttribute("android:targetActivity", mainActivityName)
// Copy all intents from the original alias so long press actions still work.
if (isYouTubeMusic) {
val intentFilter = document.createElement("intent-filter").apply {
val action = document.createElement("action")
action.setAttribute("android:name", "android.intent.action.MAIN")
appendChild(action)
val category = document.createElement("category")
category.setAttribute("android:name", "android.intent.category.LAUNCHER")
appendChild(category)
}
alias.appendChild(intentFilter)
} else {
for (i in 0 until intents.length) {
alias.appendChild(
intents.item(i).cloneNode(true)
)
}
}
return alias
}
val application = document.getElementsByTagName("application").item(0) as Element
val intentFilters = document.childNodes.findElementByAttributeValueOrThrow(
"android:name",
activityAliasNameWithIntents
).childNodes
// The YT application name can appear in some places along side the system
// YouTube app, such as the settings app list and in the "open with" file picker.
// Because the YouTube app cannot be completely uninstalled and only disabled,
// use a custom name for this situation to disambiguate which app is which.
application.setAttribute(
"android:label",
"@string/revanced_custom_branding_name_entry_2"
)
for (appNameIndex in 1 .. numberOfPresetAppNames) {
fun aliasName(name: String): String = ".revanced_" + name + '_' + appNameIndex
val useCustomNameLabel = (useCustomName && appNameIndex == numberOfPresetAppNames)
// Original icon.
application.appendChild(
createAlias(
aliasName = aliasName(ORIGINAL_USER_ICON_STYLE_NAME),
iconMipmapName = originalLauncherIconName,
appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel,
enabled = (appNameIndex == 1),
intentFilters
)
)
// Bundled icons.
iconStyleNames.forEachIndexed { index, style ->
application.appendChild(
createAlias(
aliasName = aliasName(style),
iconMipmapName = LAUNCHER_RESOURCE_NAME_PREFIX + style,
appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel,
enabled = false,
intentFilters
)
)
}
// User provided custom icon.
//
// Must add all aliases even if the user did not provide a custom icon of their own.
// This is because if the user installs with an option, then repatches without the option,
// the alias must still exist because if it was previously enabled and then it's removed
// the app will become broken and cannot launch. Even if the app data is cleared
// it still cannot be launched and the only fix is to uninstall the app.
// To prevent this, always include all aliases and use dummy data if needed.
application.appendChild(
createAlias(
aliasName = aliasName(CUSTOM_USER_ICON_STYLE_NAME),
iconMipmapName = LAUNCHER_RESOURCE_NAME_PREFIX + CUSTOM_USER_ICON_STYLE_NAME,
appNameIndex = appNameIndex,
useCustomName = useCustomNameLabel,
enabled = false,
intentFilters
)
)
}
// Remove the main action from the original alias, otherwise two apps icons
// can be shown in the launcher. Can only be done after adding the new aliases.
intentFilters.findElementByAttributeValueOrThrow(
"android:name",
"android.intent.action.MAIN"
).removeFromParent()
}
// Copy custom icons last, so if the user enters an invalid icon path
// and an exception is thrown then the critical manifest changes are still made.
if (useCustomIcon) {
// Copy user provided files
val iconPathFile = File(customIcon!!.trim())
if (!iconPathFile.exists()) {
throw PatchException(
"The custom icon path cannot be found: " + iconPathFile.absolutePath
)
}
if (!iconPathFile.isDirectory) {
throw PatchException(
"The custom icon path must be a folder: " + iconPathFile.absolutePath
)
}
val sourceFolders = iconPathFile.listFiles { file -> file.isDirectory }
?: throw PatchException("The custom icon path contains no subfolders: " +
iconPathFile.absolutePath)
val resourceDirectory = get("res")
var copiedFiles = false
// For each source folder, copy the files to the target resource directories.
sourceFolders.forEach { dpiSourceFolder ->
val targetDpiFolder = resourceDirectory.resolve(dpiSourceFolder.name)
if (!targetDpiFolder.exists()) return@forEach
val customFiles = dpiSourceFolder.listFiles { file ->
file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES
}!!
if (customFiles.size > 0 && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
throw PatchException("Must include all required icon files " +
"but only found " + customFiles.map { it.name })
}
customFiles.forEach { imgSourceFile ->
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
imgSourceFile.copyTo(target = imgTargetFile, overwrite = true)
copiedFiles = true
}
}
// Copy monochrome and small notification icon if it provided.
arrayOf(
USER_CUSTOM_MONOCHROME_FILE_NAME,
USER_CUSTOM_NOTIFICATION_ICON_FILE_NAME
).forEach { fileName ->
val relativePath = "drawable/$fileName"
val file = iconPathFile.resolve(relativePath)
if (file.exists()) {
file.copyTo(
target = resourceDirectory.resolve(relativePath),
overwrite = true
)
copiedFiles = true
}
}
if (!copiedFiles) {
throw PatchException("Could not find any replacement images in " +
"patch option path: " + iconPathFile.absolutePath)
}
}
executeBlock()
}
}

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal val numberOfPresetAppNamesExtensionFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("I")
parameters()
custom { method, classDef ->
method.name == "numberOfPresetAppNames" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}
// A much simpler fingerprint exists that can set the small icon (contains string "414843287017"),
// but that has limited usage and this fingerprint allows changing any part of the notification.
internal val notificationFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("L")
strings("key_action_priority")
}

View File

@@ -79,7 +79,7 @@ internal val darkThemeBackgroundColorOption = stringOption(
*/ */
internal fun baseThemePatch( internal fun baseThemePatch(
extensionClassDescriptor: String, extensionClassDescriptor: String,
block: BytecodePatchBuilder.() -> Unit = {}, block: BytecodePatchBuilder.() -> Unit,
executeBlock: BytecodePatchContext.() -> Unit = {} executeBlock: BytecodePatchContext.() -> Unit = {}
) = bytecodePatch( ) = bytecodePatch(
name = "Theme", name = "Theme",

View File

@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.video.audio package app.revanced.patches.shared.misc.audio
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction import app.revanced.util.containsLiteralInstruction
@@ -7,10 +7,14 @@ import com.android.tools.smali.dexlib2.AccessFlags
internal val formatStreamModelToStringFingerprint = fingerprint { internal val formatStreamModelToStringFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Ljava/lang/String;") returns("Ljava/lang/String;")
custom { method, classDef -> custom { method, _ ->
method.name == "toString" && classDef.type == method.name == "toString"
"Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;"
} }
strings(
// Strings are partial matches.
"isDefaultAudioTrack=",
"audioTrackId="
)
} }
internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L
@@ -20,7 +24,6 @@ internal val selectAudioStreamFingerprint = fingerprint {
returns("L") returns("L")
custom { method, _ -> custom { method, _ ->
method.parameters.size > 2 // Method has a large number of parameters and may change. method.parameters.size > 2 // Method has a large number of parameters and may change.
&& method.parameters[1].type == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
&& method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG) && method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG)
} }
} }

View File

@@ -0,0 +1,157 @@
package app.revanced.patches.shared.misc.audio
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.util.findMethodFromToString
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.insertLiteralOverride
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableField
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/patches/ForceOriginalAudioPatch;"
/**
* Patch shared with YouTube and YT Music.
*/
internal fun forceOriginalAudioPatch(
block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {},
fixUseLocalizedAudioTrackFlag: Boolean,
mainActivityOnCreateFingerprint: Fingerprint,
subclassExtensionClassDescriptor: String,
preferenceScreen: BasePreferenceScreen.Screen
) = bytecodePatch(
name = "Force original audio",
description = "Adds an option to always use the original audio track.",
) {
block()
dependsOn(addResourcesPatch)
execute {
addResources("shared", "misc.audio.forceOriginalAudioPatch")
preferenceScreen.addPreferences(
SwitchPreference(
key = "revanced_force_original_audio",
tag = "app.revanced.extension.shared.settings.preference.ForceOriginalAudioSwitchPreference"
)
)
mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $subclassExtensionClassDescriptor->setEnabled()V"
)
// Disable feature flag that ignores the default track flag
// and instead overrides to the user region language.
if (fixUseLocalizedAudioTrackFlag) {
selectAudioStreamFingerprint.method.insertLiteralOverride(
AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->ignoreDefaultAudioStream(Z)Z"
)
}
formatStreamModelToStringFingerprint.let {
val isDefaultAudioTrackMethod = it.originalMethod.findMethodFromToString("isDefaultAudioTrack=")
val audioTrackDisplayNameMethod = it.originalMethod.findMethodFromToString("audioTrackDisplayName=")
val audioTrackIdMethod = it.originalMethod.findMethodFromToString("audioTrackId=")
it.classDef.apply {
// Add a new field to store the override.
val helperFieldName = "patch_isDefaultAudioTrackOverride"
fields.add(
ImmutableField(
type,
helperFieldName,
"Ljava/lang/Boolean;",
// Boolean is a 100% immutable class (all fields are final)
// and safe to write to a shared field without volatile/synchronization,
// but without volatile the field can show stale data
// and the same field is calculated more than once by different threads.
AccessFlags.PRIVATE.value or AccessFlags.VOLATILE.value,
null,
null,
null
).toMutable()
)
// Add a helper method because the isDefaultAudioTrack() has only 2 registers and 3 are needed.
val helperMethodClass = type
val helperMethodName = "patch_isDefaultAudioTrack"
val helperMethod = ImmutableMethod(
helperMethodClass,
helperMethodName,
listOf(ImmutableMethodParameter("Z", null, null)),
"Z",
AccessFlags.PRIVATE.value,
null,
null,
MutableMethodImplementation(6),
).toMutable().apply {
addInstructionsWithLabels(
0,
"""
iget-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean;
if-eqz v0, :call_extension
invoke-virtual { v0 }, Ljava/lang/Boolean;->booleanValue()Z
move-result v3
return v3
:call_extension
invoke-virtual { p0 }, $audioTrackIdMethod
move-result-object v1
invoke-virtual { p0 }, $audioTrackDisplayNameMethod
move-result-object v2
invoke-static { p1, v1, v2 }, $EXTENSION_CLASS_DESCRIPTOR->isDefaultAudioStream(ZLjava/lang/String;Ljava/lang/String;)Z
move-result v3
invoke-static { v3 }, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
move-result-object v0
iput-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean;
return v3
"""
)
}
methods.add(helperMethod)
// Modify isDefaultAudioTrack() to call extension helper method.
isDefaultAudioTrackMethod.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.RETURN)
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index,
"""
invoke-direct { p0, v$register }, $helperMethodClass->$helperMethodName(Z)Z
move-result v$register
"""
)
}
}
}
executeBlock()
}
}

View File

@@ -1,16 +1,11 @@
package app.revanced.patches.shared.misc.gms package app.revanced.patches.shared.misc.gms
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.patches.shared.misc.gms.EXTENSION_CLASS_DESCRIPTOR
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
const val GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME = "getGmsCoreVendorGroupId" const val GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME = "getGmsCoreVendorGroupId"
internal val gmsCoreSupportFingerprint = fingerprint {
custom { _, classDef ->
classDef.endsWith("GmsCoreSupport;")
}
}
internal val googlePlayUtilityFingerprint = fingerprint { internal val googlePlayUtilityFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("I") returns("I")
@@ -28,3 +23,21 @@ internal val serviceCheckFingerprint = fingerprint {
parameters("L", "I") parameters("L", "I")
strings("Google Play Services not available") strings("Google Play Services not available")
} }
internal val gmsCoreSupportFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { method, classDef ->
method.name == "getGmsCoreVendorGroupId" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}
internal val originalPackageNameExtensionFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { methodDef, classDef ->
methodDef.name == "getOriginalPackageName" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
}

View File

@@ -1,10 +1,18 @@
package app.revanced.patches.shared.misc.gms package app.revanced.patches.shared.misc.gms
import app.revanced.patcher.Fingerprint import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.* import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Option
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.ResourcePatchBuilder
import app.revanced.patcher.patch.ResourcePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.packagename.changePackageNamePatch import app.revanced.patches.all.misc.packagename.changePackageNamePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
@@ -12,7 +20,8 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.gms.Constants.ACTIONS import app.revanced.patches.shared.misc.gms.Constants.ACTIONS
import app.revanced.patches.shared.misc.gms.Constants.AUTHORITIES import app.revanced.patches.shared.misc.gms.Constants.AUTHORITIES
import app.revanced.patches.shared.misc.gms.Constants.PERMISSIONS import app.revanced.patches.shared.misc.gms.Constants.PERMISSIONS
import app.revanced.util.* import app.revanced.util.getReference
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@@ -23,6 +32,8 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
import org.w3c.dom.Element import org.w3c.dom.Element
import org.w3c.dom.Node import org.w3c.dom.Node
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/GmsCoreSupport;"
private const val PACKAGE_NAME_REGEX_PATTERN = "^[a-z]\\w*(\\.[a-z]\\w*)+\$" private const val PACKAGE_NAME_REGEX_PATTERN = "^[a-z]\\w*(\\.[a-z]\\w*)+\$"
/** /**
@@ -201,19 +212,18 @@ fun gmsCoreSupportPatch(
googlePlayUtilityFingerprint.method.returnEarly(0) googlePlayUtilityFingerprint.method.returnEarly(0)
} }
// Set original and patched package names for extension to use.
originalPackageNameExtensionFingerprint.method.returnEarly(fromPackageName)
// Verify GmsCore is installed and whitelisted for power optimizations and background usage. // Verify GmsCore is installed and whitelisted for power optimizations and background usage.
mainActivityOnCreateFingerprint.method.apply { mainActivityOnCreateFingerprint.method.addInstruction(
addInstructions( 0,
0, "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"invoke-static/range { p0 .. p0 }, Lapp/revanced/extension/shared/GmsCoreSupport;->" + "checkGmsCore(Landroid/app/Activity;)V"
"checkGmsCore(Landroid/app/Activity;)V", )
)
}
// Change the vendor of GmsCore in the extension. // Change the vendor of GmsCore in the extension.
gmsCoreSupportFingerprint.classDef.methods gmsCoreSupportFingerprint.method.returnEarly(gmsCoreVendorGroupId!!)
.single { it.name == GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME }
.replaceInstruction(0, "const-string v0, \"$gmsCoreVendorGroupId\"")
executeBlock() executeBlock()
} }

View File

@@ -10,6 +10,8 @@ import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory 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.PreferenceScreenPreference.Sorting
@@ -20,14 +22,17 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/patches/SanitizeSharingLinksPatch;" "Lapp/revanced/extension/shared/patches/SanitizeSharingLinksPatch;"
/**
* Patch shared by YouTube and YT Music.
*/
internal fun sanitizeSharingLinksPatch( internal fun sanitizeSharingLinksPatch(
block: BytecodePatchBuilder.() -> Unit = {}, block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {}, executeBlock: BytecodePatchContext.() -> Unit = {},
preferenceScreen: BasePreferenceScreen.Screen, preferenceScreen: BasePreferenceScreen.Screen,
replaceMusicLinksWithYouTube: Boolean = false replaceMusicLinksWithYouTube: Boolean = false
) = bytecodePatch( ) = bytecodePatch(
name = "Sanitize sharing links", name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = "Adds an option to remove the tracking query parameter from shared links.", description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
) { ) {
block() block()

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.shared.misc.spoof package app.revanced.patches.shared.misc.spoof
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
@@ -36,11 +37,13 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
private lateinit var buildRequestMethod: MutableMethod private lateinit var buildRequestMethod: MutableMethod
private var buildRequestMethodUrlRegister = -1 private var buildRequestMethodUrlRegister = -1
fun spoofVideoStreamsPatch( internal fun spoofVideoStreamsPatch(
block: BytecodePatchBuilder.() -> Unit = {}, extensionClassDescriptor: String,
fixMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false }, mainActivityOnCreateFingerprint: Fingerprint,
fixMediaFetchHotConfigAlternativeChanges: BytecodePatchBuilder.() -> Boolean = { false }, fixMediaFetchHotConfig: BytecodePatchBuilder.() -> Boolean = { false },
fixMediaFetchHotConfigAlternative: BytecodePatchBuilder.() -> Boolean = { false },
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false }, fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
block: BytecodePatchBuilder.() -> Unit,
executeBlock: BytecodePatchContext.() -> Unit = {}, executeBlock: BytecodePatchContext.() -> Unit = {},
) = bytecodePatch( ) = bytecodePatch(
name = "Spoof video streams", name = "Spoof video streams",
@@ -53,6 +56,11 @@ fun spoofVideoStreamsPatch(
execute { execute {
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch") addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $extensionClassDescriptor->setClientOrderToUse()V"
)
// region Enable extension helper method used by other patches // region Enable extension helper method used by other patches
patchIncludedExtensionMethodFingerprint.method.returnEarly(true) patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
@@ -308,14 +316,14 @@ fun spoofVideoStreamsPatch(
// region turn off stream config replacement feature flag. // region turn off stream config replacement feature flag.
if (fixMediaFetchHotConfigChanges()) { if (fixMediaFetchHotConfig()) {
mediaFetchHotConfigFingerprint.method.insertLiteralOverride( mediaFetchHotConfigFingerprint.method.insertLiteralOverride(
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG, MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
) )
} }
if (fixMediaFetchHotConfigAlternativeChanges()) { if (fixMediaFetchHotConfigAlternative()) {
mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride( mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride(
MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG, MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z" "$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"

View File

@@ -17,7 +17,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused") @Suppress("unused")
val hideCreateButtonPatch = bytecodePatch( val hideCreateButtonPatch = bytecodePatch(
name = "Hide Create button", name = "Hide Create button",
description = "Hides the \"Create\" button in the navigation bar." description = "Hides the \"Create\" button in the navigation bar. The latest app targets do not need this patch.",
use = false
) { ) {
compatibleWith("com.spotify.music") compatibleWith("com.spotify.music")

View File

@@ -3,6 +3,8 @@ package app.revanced.patches.spotify.misc.privacy
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -15,8 +17,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused") @Suppress("unused")
val sanitizeSharingLinksPatch = bytecodePatch( val sanitizeSharingLinksPatch = bytecodePatch(
name = "Sanitize sharing links", name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = "Removes the tracking query parameters from links before they are shared.", description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
) { ) {
compatibleWith("com.spotify.music") compatibleWith("com.spotify.music")
@@ -24,7 +26,7 @@ val sanitizeSharingLinksPatch = bytecodePatch(
execute { execute {
val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->" + val extensionMethodDescriptor = "$EXTENSION_CLASS_DESCRIPTOR->" +
"sanitizeUrl(Ljava/lang/String;)Ljava/lang/String;" "sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;"
val copyFingerprint = if (shareCopyUrlFingerprint.originalMethodOrNull != null) { val copyFingerprint = if (shareCopyUrlFingerprint.originalMethodOrNull != null) {
shareCopyUrlFingerprint shareCopyUrlFingerprint

View File

@@ -12,9 +12,8 @@ val dynamicColorPatch = resourcePatch(
) { ) {
compatibleWith( compatibleWith(
"com.twitter.android"( "com.twitter.android"(
"10.86.0-release.0",
"10.60.0-release.0", "10.60.0-release.0",
"10.48.0-release.0" "10.86.0-release.0",
) )
) )

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.twitter.misc.extension package app.revanced.patches.twitter.misc.extension
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
import app.revanced.patches.twitter.misc.extension.hooks.applicationInitHook
val sharedExtensionPatch = sharedExtensionPatch("twitter") val sharedExtensionPatch = sharedExtensionPatch("twitter", applicationInitHook)

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