mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 01:51:27 +01:00
Compare commits
54 Commits
v5.42.0-de
...
v5.42.2-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8c4bdb8a6 | ||
|
|
6555f6e6f8 | ||
|
|
a0e2c5c7b9 | ||
|
|
54846253d7 | ||
|
|
a98e8f7370 | ||
|
|
2d928e0cd6 | ||
|
|
be2b144cc9 | ||
|
|
52c0bb6aa2 | ||
|
|
38a49cc2a1 | ||
|
|
91044b3a50 | ||
|
|
fd4b2e1bb9 | ||
|
|
d0f20c8c7f | ||
|
|
d65dbc749c | ||
|
|
143dcef2b8 | ||
|
|
dbfc5be464 | ||
|
|
0fe545cad6 | ||
|
|
feca17be68 | ||
|
|
7afeaebb5c | ||
|
|
60a581a632 | ||
|
|
104d096ada | ||
|
|
19dcbd8efb | ||
|
|
a50f3b5177 | ||
|
|
64d22a9c31 | ||
|
|
bd4ba2dae8 | ||
|
|
f51b260d1d | ||
|
|
63be54dd09 | ||
|
|
bb222d7a26 | ||
|
|
f03256c471 | ||
|
|
fe16433f20 | ||
|
|
2154d89242 | ||
|
|
277a8b6b47 | ||
|
|
20c413120b | ||
|
|
5ed092bb7d | ||
|
|
19949e1695 | ||
|
|
ec0acc0f13 | ||
|
|
a30a849e6e | ||
|
|
603025a122 | ||
|
|
9441e7acb4 | ||
|
|
963a4ef43f | ||
|
|
0acba30245 | ||
|
|
6b26346914 | ||
|
|
b1511c732d | ||
|
|
26117e744c | ||
|
|
a62ee43441 | ||
|
|
6a799110d7 | ||
|
|
aec17b93f7 | ||
|
|
e7a1706be4 | ||
|
|
9469604fe0 | ||
|
|
1a3a12df1a | ||
|
|
ae4b9474d3 | ||
|
|
83ccd9d3f1 | ||
|
|
526c7c05e2 | ||
|
|
d0d53d109e | ||
|
|
9d6731660b |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
run: ./gradlew :patches:buildAndroid clean
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'npm'
|
||||
|
||||
195
CHANGELOG.md
195
CHANGELOG.md
@@ -1,3 +1,198 @@
|
||||
## [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)
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,6 @@ public class Settings extends BaseSettings {
|
||||
// Miscellaneous
|
||||
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 FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ import app.revanced.extension.shared.ui.CustomDialog;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
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
|
||||
= getGmsCoreVendorGroupId() + ".android.gms";
|
||||
private static final Uri GMS_CORE_PROVIDER
|
||||
@@ -53,6 +50,20 @@ public class GmsCoreSupport {
|
||||
@Nullable
|
||||
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) {
|
||||
Logger.printInfo(() -> "Opening link: " + queryOrLink);
|
||||
|
||||
@@ -113,11 +124,10 @@ public class GmsCoreSupport {
|
||||
// Verify the user has not included GmsCore for a root installation.
|
||||
// GmsCore Support changes the package name, but with a mounted installation
|
||||
// all manifest changes are ignored and the original package name is used.
|
||||
String packageName = context.getPackageName();
|
||||
if (packageName.equals(PACKAGE_NAME_YOUTUBE) || packageName.equals(PACKAGE_NAME_YOUTUBE_MUSIC)) {
|
||||
if (isPackageNameOriginal()) {
|
||||
Logger.printInfo(() -> "App is mounted with root, but GmsCore patch was included");
|
||||
// Cannot use localize text here, since the app will load
|
||||
// resources from the unpatched app and all patch strings are missing.
|
||||
// Cannot use localize text here, since the app will load resources
|
||||
// from the unpatched app and all patch strings are missing.
|
||||
Utils.showToastLong("The 'GmsCore support' patch breaks mount installations");
|
||||
|
||||
// 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() {
|
||||
return "app.revanced";
|
||||
return "app.revanced"; // Modified during patching.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
package app.revanced.extension.shared.patches;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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. Must be first enum.
|
||||
*/
|
||||
ORIGINAL("revanced_original"),
|
||||
ROUNDED("revanced_rounded"),
|
||||
MINIMAL("revanced_minimal"),
|
||||
SCALED("revanced_scaled"),
|
||||
/**
|
||||
* User provided custom icon. Must be the last enum.
|
||||
*/
|
||||
CUSTOM("revanced_custom");
|
||||
|
||||
public final String themeAlias;
|
||||
|
||||
BrandingTheme(String themeAlias) {
|
||||
this.themeAlias = themeAlias;
|
||||
}
|
||||
|
||||
private String packageAndNameIndexToClassAlias(String packageName, int appIndex) {
|
||||
if (appIndex <= 0) {
|
||||
throw new IllegalArgumentException("App index starts at index 1");
|
||||
}
|
||||
return packageName + '.' + themeAlias + '_' + appIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package app.revanced.extension.shared.patches;
|
||||
|
||||
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
|
||||
/**
|
||||
@@ -7,17 +8,18 @@ import app.revanced.extension.shared.settings.BaseSettings;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
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.
|
||||
*/
|
||||
public static String sanitize(String url) {
|
||||
if (BaseSettings.SANITIZE_SHARED_LINKS.get()) {
|
||||
url = url
|
||||
.replaceAll(NEW_TRACKING_PARAMETER_REGEX, "")
|
||||
.replaceAll(OLD_TRACKING_PARAMETER_REGEX, "");
|
||||
url = sanitizer.sanitizeUrlString(url);
|
||||
}
|
||||
|
||||
if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,8 +36,8 @@ public enum AppLanguage {
|
||||
FR,
|
||||
GL,
|
||||
GU,
|
||||
HI,
|
||||
HE, // App uses obsolete 'IW' and not the modern 'HE' ISO code.
|
||||
HI,
|
||||
HR,
|
||||
HU,
|
||||
HY,
|
||||
@@ -60,9 +60,9 @@ public enum AppLanguage {
|
||||
MR,
|
||||
MS,
|
||||
MY,
|
||||
NB,
|
||||
NE,
|
||||
NL,
|
||||
NB,
|
||||
OR,
|
||||
PA,
|
||||
PL,
|
||||
|
||||
@@ -2,6 +2,7 @@ package app.revanced.extension.shared.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
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.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 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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,17 +6,17 @@ import android.content.Context;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings({"deprecation", "unused"})
|
||||
public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
|
||||
|
||||
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
|
||||
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|
||||
|| !(Settings.SPOOF_VIDEO_STREAMS.get()
|
||||
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR);
|
||||
|| !(BaseSettings.SPOOF_VIDEO_STREAMS.get()
|
||||
&& SpoofVideoStreamsPatch.getPreferredClient() == ClientType.ANDROID_CREATOR);
|
||||
|
||||
{
|
||||
if (!available) {
|
||||
@@ -5,6 +5,7 @@ import static app.revanced.extension.shared.Utils.dipToPixels;
|
||||
import static app.revanced.extension.shared.requests.Route.Method.GET;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
@@ -125,6 +126,8 @@ public class ReVancedAboutPreference extends Preference {
|
||||
|
||||
{
|
||||
setOnPreferenceClickListener(pref -> {
|
||||
Context context = pref.getContext();
|
||||
|
||||
// Show a progress spinner if the social links are not fetched yet.
|
||||
if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
||||
// 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);
|
||||
|
||||
Utils.runOnBackgroundThread(() ->
|
||||
fetchLinksAndShowDialog(handler, showDialogRunnable, progress));
|
||||
fetchLinksAndShowDialog(context, handler, showDialogRunnable, progress));
|
||||
} else {
|
||||
// No network call required and can run now.
|
||||
fetchLinksAndShowDialog(null, null, null);
|
||||
fetchLinksAndShowDialog(context, null, null, null);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
private void fetchLinksAndShowDialog(@Nullable Handler handler,
|
||||
private void fetchLinksAndShowDialog(Context context,
|
||||
@Nullable Handler handler,
|
||||
Runnable showDialogRunnable,
|
||||
@Nullable ProgressDialog progress) {
|
||||
WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
|
||||
@@ -164,7 +168,17 @@ public class ReVancedAboutPreference extends Preference {
|
||||
if (handler != null) {
|
||||
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();
|
||||
}
|
||||
new WebViewDialog(getContext(), htmlDialog).show();
|
||||
|
||||
@@ -31,6 +31,7 @@ public enum ClientType {
|
||||
"132.0.6808.3",
|
||||
"1.61.48",
|
||||
false,
|
||||
false,
|
||||
"Android VR 1.61"
|
||||
),
|
||||
/**
|
||||
@@ -50,6 +51,7 @@ public enum ClientType {
|
||||
"107.0.5284.2",
|
||||
"1.43.32",
|
||||
ANDROID_VR_1_61_48.useAuth,
|
||||
ANDROID_VR_1_61_48.supportsMultiAudioTracks,
|
||||
"Android VR 1.43"
|
||||
),
|
||||
/**
|
||||
@@ -69,6 +71,7 @@ public enum ClientType {
|
||||
"132.0.6779.0",
|
||||
"23.47.101",
|
||||
true,
|
||||
false,
|
||||
"Android Studio"
|
||||
),
|
||||
/**
|
||||
@@ -83,6 +86,7 @@ public enum ClientType {
|
||||
"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",
|
||||
false,
|
||||
false,
|
||||
"visionOS"
|
||||
),
|
||||
/**
|
||||
@@ -107,6 +111,7 @@ public enum ClientType {
|
||||
"19.22.3",
|
||||
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
|
||||
false,
|
||||
true,
|
||||
"iPadOS"
|
||||
);
|
||||
|
||||
@@ -180,6 +185,11 @@ public enum ClientType {
|
||||
*/
|
||||
public final boolean useAuth;
|
||||
|
||||
/**
|
||||
* If the client supports multiple audio tracks.
|
||||
*/
|
||||
public final boolean supportsMultiAudioTracks;
|
||||
|
||||
/**
|
||||
* Friendly name displayed in stats for nerds.
|
||||
*/
|
||||
@@ -200,6 +210,7 @@ public enum ClientType {
|
||||
@NonNull String cronetVersion,
|
||||
String clientVersion,
|
||||
boolean useAuth,
|
||||
boolean supportsMultiAudioTracks,
|
||||
String friendlyName) {
|
||||
this.id = id;
|
||||
this.clientName = clientName;
|
||||
@@ -213,6 +224,7 @@ public enum ClientType {
|
||||
this.cronetVersion = cronetVersion;
|
||||
this.clientVersion = clientVersion;
|
||||
this.useAuth = useAuth;
|
||||
this.supportsMultiAudioTracks = supportsMultiAudioTracks;
|
||||
this.friendlyName = friendlyName;
|
||||
|
||||
Locale defaultLocale = Locale.getDefault();
|
||||
@@ -238,6 +250,7 @@ public enum ClientType {
|
||||
String clientVersion,
|
||||
String userAgent,
|
||||
boolean useAuth,
|
||||
boolean supportsMultiAudioTracks,
|
||||
String friendlyName) {
|
||||
this.id = id;
|
||||
this.clientName = clientName;
|
||||
@@ -248,6 +261,7 @@ public enum ClientType {
|
||||
this.clientVersion = clientVersion;
|
||||
this.userAgent = userAgent;
|
||||
this.useAuth = useAuth;
|
||||
this.supportsMultiAudioTracks = supportsMultiAudioTracks;
|
||||
this.friendlyName = friendlyName;
|
||||
this.packageName = null;
|
||||
this.androidSdkVersion = null;
|
||||
|
||||
@@ -19,6 +19,14 @@ import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
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.
|
||||
* 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
|
||||
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.
|
||||
@@ -66,6 +74,10 @@ public class SpoofVideoStreamsPatch {
|
||||
StreamingDataRequest.setClientOrderToUse(availableClients, client);
|
||||
}
|
||||
|
||||
public static ClientType getPreferredClient() {
|
||||
return preferredClient;
|
||||
}
|
||||
|
||||
public static boolean spoofingToClientWithNoMultiAudioStreams() {
|
||||
return isPatchIncluded()
|
||||
&& SPOOF_STREAMING_DATA
|
||||
@@ -317,11 +329,4 @@ public class SpoofVideoStreamsPatch {
|
||||
|
||||
return videoFormat;
|
||||
}
|
||||
|
||||
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
package app.revanced.extension.spotify.misc.privacy;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class SanitizeSharingLinksPatch {
|
||||
|
||||
/**
|
||||
* Parameters that are considered undesirable and should be stripped away.
|
||||
*/
|
||||
private static final List<String> SHARE_PARAMETERS_TO_REMOVE = List.of(
|
||||
private static final LinkSanitizer sanitizer = new LinkSanitizer(
|
||||
"si", // Share tracking parameter.
|
||||
"utm_source" // Share source, such as "copy-link".
|
||||
);
|
||||
@@ -20,25 +13,7 @@ public final class SanitizeSharingLinksPatch {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String sanitizeUrl(String url) {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
public static String sanitizeSharingLink(String url) {
|
||||
return sanitizer.sanitizeUrlString(url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,19 @@ package app.revanced.twitter.patches.links;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ChangeLinkSharingDomainPatch {
|
||||
private static final String DOMAIN_NAME = "https://fxtwitter.com";
|
||||
private static final String LINK_FORMAT = "%s/%s/status/%s";
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Method is modified during patching. Do not change.
|
||||
*/
|
||||
public static String formatResourceLink(Object... formatArgs) {
|
||||
String username = (String) formatArgs[0];
|
||||
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) {
|
||||
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
||||
return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,17 @@
|
||||
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;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ForceOriginalAudioPatch {
|
||||
|
||||
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setPreferredLanguage() {
|
||||
if (Settings.FORCE_ORIGINAL_AUDIO.get()
|
||||
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()
|
||||
&& !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) {
|
||||
// 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;
|
||||
}
|
||||
public static void setEnabled() {
|
||||
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
|
||||
Settings.FORCE_ORIGINAL_AUDIO.get(),
|
||||
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,11 +131,11 @@ public class ReturnYouTubeDislikePatch {
|
||||
|
||||
String conversionContextString = conversionContext.toString();
|
||||
|
||||
if (isRollingNumber && !conversionContextString.contains("video_action_bar.eml")) {
|
||||
if (isRollingNumber && !conversionContextString.contains("video_action_bar.e")) {
|
||||
return original;
|
||||
}
|
||||
|
||||
if (conversionContextString.contains("segmented_like_dislike_button.eml")) {
|
||||
if (conversionContextString.contains("segmented_like_dislike_button.e")) {
|
||||
// Regular video.
|
||||
ReturnYouTubeDislike videoData = currentVideoData;
|
||||
if (videoData == null) {
|
||||
@@ -153,12 +153,12 @@ public class ReturnYouTubeDislikePatch {
|
||||
}
|
||||
|
||||
if (Utils.containsAny(conversionContextString,
|
||||
"|shorts_dislike_button.eml", "|reel_dislike_button.eml")) {
|
||||
"|shorts_dislike_button.e", "|reel_dislike_button.e")) {
|
||||
return getShortsSpan(original, true);
|
||||
}
|
||||
|
||||
if (Utils.containsAny(conversionContextString,
|
||||
"|shorts_like_button.eml", "|reel_like_button.eml")) {
|
||||
"|shorts_like_button.e", "|reel_like_button.e")) {
|
||||
if (!Utils.containsNumber(original)) {
|
||||
Logger.printDebug(() -> "Replacing hidden likes count");
|
||||
return getShortsSpan(original, false);
|
||||
|
||||
@@ -105,17 +105,17 @@ public final class AdsFilter extends Filter {
|
||||
Settings.HIDE_VIEW_PRODUCTS_BANNER,
|
||||
"product_item",
|
||||
"products_in_video",
|
||||
"shopping_overlay.eml" // Video player overlay shopping links.
|
||||
"shopping_overlay.e" // Video player overlay shopping links.
|
||||
);
|
||||
|
||||
final var shoppingLinks = new StringFilterGroup(
|
||||
Settings.HIDE_SHOPPING_LINKS,
|
||||
"shopping_description_shelf.eml"
|
||||
"shopping_description_shelf.e"
|
||||
);
|
||||
|
||||
playerShoppingShelf = new StringFilterGroup(
|
||||
Settings.HIDE_CREATOR_STORE_SHELF,
|
||||
"horizontal_shelf.eml"
|
||||
"horizontal_shelf.e"
|
||||
);
|
||||
|
||||
playerShoppingShelfBuffer = new ByteArrayFilterGroup(
|
||||
@@ -131,7 +131,7 @@ public final class AdsFilter extends Filter {
|
||||
final var merchandise = new StringFilterGroup(
|
||||
Settings.HIDE_MERCHANDISE_BANNERS,
|
||||
"product_carousel",
|
||||
"shopping_carousel.eml" // Channel profile shopping shelf.
|
||||
"shopping_carousel.e" // Channel profile shopping shelf.
|
||||
);
|
||||
|
||||
final var selfSponsor = new StringFilterGroup(
|
||||
|
||||
@@ -14,7 +14,7 @@ public final class AdvancedVideoQualityMenuFilter extends Filter {
|
||||
public AdvancedVideoQualityMenuFilter() {
|
||||
addPathCallbacks(new StringFilterGroup(
|
||||
Settings.ADVANCED_VIDEO_QUALITY_MENU,
|
||||
"quick_quality_sheet_content.eml-js"
|
||||
"quick_quality_sheet_content.e"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final class ButtonsFilter extends Filter {
|
||||
private static final String COMPACT_CHANNEL_BAR_PATH_PREFIX = "compact_channel_bar.eml";
|
||||
private static final String VIDEO_ACTION_BAR_PATH_PREFIX = "video_action_bar.eml";
|
||||
private static final String VIDEO_ACTION_BAR_PATH = "video_action_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.e";
|
||||
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+
|
||||
*/
|
||||
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 final StringFilterGroup likeSubscribeGlow;
|
||||
@@ -28,12 +28,12 @@ final class ButtonsFilter extends Filter {
|
||||
|
||||
likeSubscribeGlow = new StringFilterGroup(
|
||||
Settings.DISABLE_LIKE_SUBSCRIBE_GLOW,
|
||||
"animated_button_border.eml"
|
||||
"animated_button_border.e"
|
||||
);
|
||||
|
||||
bufferFilterPathGroup = new StringFilterGroup(
|
||||
null,
|
||||
"|ContainerType|button.eml"
|
||||
"|ContainerType|button.e"
|
||||
);
|
||||
|
||||
addPathCallbacks(
|
||||
@@ -45,7 +45,7 @@ final class ButtonsFilter extends Filter {
|
||||
),
|
||||
new StringFilterGroup(
|
||||
Settings.HIDE_DOWNLOAD_BUTTON,
|
||||
"|download_button.eml"
|
||||
"|download_button.e"
|
||||
),
|
||||
new StringFilterGroup(
|
||||
Settings.HIDE_SAVE_BUTTON,
|
||||
@@ -53,7 +53,7 @@ final class ButtonsFilter extends Filter {
|
||||
),
|
||||
new StringFilterGroup(
|
||||
Settings.HIDE_CLIP_BUTTON,
|
||||
"|clip_button.eml"
|
||||
"|clip_button.e"
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import app.revanced.extension.youtube.shared.PlayerType;
|
||||
@SuppressWarnings("unused")
|
||||
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 ByteArrayFilterGroup aiCommentsSummary;
|
||||
@@ -15,12 +15,12 @@ final class CommentsFilter extends Filter {
|
||||
public CommentsFilter() {
|
||||
var chatSummary = new StringFilterGroup(
|
||||
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
|
||||
"live_chat_summary_banner.eml"
|
||||
"live_chat_summary_banner.e"
|
||||
);
|
||||
|
||||
chipBar = new StringFilterGroup(
|
||||
Settings.HIDE_COMMENTS_AI_SUMMARY,
|
||||
"chip_bar.eml"
|
||||
"chip_bar.e"
|
||||
);
|
||||
|
||||
aiCommentsSummary = new ByteArrayFilterGroup(
|
||||
@@ -35,8 +35,8 @@ final class CommentsFilter extends Filter {
|
||||
|
||||
var commentsByMembers = new StringFilterGroup(
|
||||
Settings.HIDE_COMMENTS_BY_MEMBERS_HEADER,
|
||||
"sponsorships_comments_header.eml",
|
||||
"sponsorships_comments_footer.eml"
|
||||
"sponsorships_comments_header.e",
|
||||
"sponsorships_comments_footer.e"
|
||||
);
|
||||
|
||||
var comments = new StringFilterGroup(
|
||||
@@ -52,7 +52,7 @@ final class CommentsFilter extends Filter {
|
||||
|
||||
var createAShort = new StringFilterGroup(
|
||||
Settings.HIDE_COMMENTS_CREATE_A_SHORT_BUTTON,
|
||||
"composer_short_creation_button.eml"
|
||||
"composer_short_creation_button.e"
|
||||
);
|
||||
|
||||
emojiAndTimestampButtons = new StringFilterGroup(
|
||||
@@ -69,7 +69,7 @@ final class CommentsFilter extends Filter {
|
||||
|
||||
var thanksButton = new StringFilterGroup(
|
||||
Settings.HIDE_COMMENTS_THANKS_BUTTON,
|
||||
"super_thanks_button.eml"
|
||||
"super_thanks_button.e"
|
||||
);
|
||||
|
||||
addPathCallbacks(
|
||||
|
||||
@@ -29,12 +29,12 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
|
||||
aiGeneratedVideoSummarySection = new StringFilterGroup(
|
||||
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
|
||||
"cell_expandable_metadata.eml"
|
||||
"cell_expandable_metadata.e"
|
||||
);
|
||||
|
||||
final StringFilterGroup askSection = new StringFilterGroup(
|
||||
Settings.HIDE_ASK_SECTION,
|
||||
"youchat_entrypoint.eml"
|
||||
"youchat_entrypoint.e"
|
||||
);
|
||||
|
||||
final StringFilterGroup attributesSection = new StringFilterGroup(
|
||||
@@ -65,7 +65,7 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
|
||||
macroMarkersCarousel = new StringFilterGroup(
|
||||
null,
|
||||
"macro_markers_carousel.eml"
|
||||
"macro_markers_carousel.e"
|
||||
);
|
||||
|
||||
macroMarkersCarouselGroupList.addAll(
|
||||
@@ -81,7 +81,7 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
|
||||
horizontalShelf = new StringFilterGroup(
|
||||
Settings.HIDE_ATTRIBUTES_SECTION,
|
||||
"horizontal_shelf.eml"
|
||||
"horizontal_shelf.e"
|
||||
);
|
||||
|
||||
cellVideoAttribute = new ByteArrayFilterGroup(
|
||||
|
||||
@@ -9,7 +9,7 @@ public final class HideInfoCardsFilter extends Filter {
|
||||
addIdentifierCallbacks(
|
||||
new StringFilterGroup(
|
||||
Settings.HIDE_INFO_CARDS,
|
||||
"info_card_teaser_overlay.eml"
|
||||
"info_card_teaser_overlay.e"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -79,10 +79,10 @@ final class KeywordContentFilter extends Filter {
|
||||
"search_vwc_description_transition_key",
|
||||
"g-high-recZ",
|
||||
// Text and litho components found in the buffer that belong to path filters.
|
||||
"expandable_metadata.eml",
|
||||
"thumbnail.eml",
|
||||
"avatar.eml",
|
||||
"overflow_button.eml",
|
||||
"expandable_metadata.e",
|
||||
"thumbnail.e",
|
||||
"avatar.e",
|
||||
"overflow_button.e",
|
||||
"shorts-lockup-image",
|
||||
"shorts-lockup.overlay-metadata.secondary-text",
|
||||
"YouTubeSans-SemiBold",
|
||||
@@ -94,16 +94,16 @@ final class KeywordContentFilter extends Filter {
|
||||
*/
|
||||
private final StringFilterGroup startsWithFilter = new StringFilterGroup(
|
||||
null, // Multiple settings are used and must be individually checked if active.
|
||||
"home_video_with_context.eml",
|
||||
"search_video_with_context.eml",
|
||||
"video_with_context.eml", // Subscription tab videos.
|
||||
"related_video_with_context.eml",
|
||||
"home_video_with_context.e",
|
||||
"search_video_with_context.e",
|
||||
"video_with_context.e", // Subscription tab videos.
|
||||
"related_video_with_context.e",
|
||||
// A/B test for subscribed video, and sometimes when tablet layout is enabled.
|
||||
"video_lockup_with_attachment.eml",
|
||||
"compact_video.eml",
|
||||
"video_lockup_with_attachment.e",
|
||||
"compact_video.e",
|
||||
"inline_shorts",
|
||||
"shorts_video_cell",
|
||||
"shorts_pivot_item.eml"
|
||||
"shorts_pivot_item.e"
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -112,9 +112,9 @@ final class KeywordContentFilter extends Filter {
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private final StringFilterGroup containsFilter = new StringFilterGroup(
|
||||
null,
|
||||
"modern_type_shelf_header_content.eml",
|
||||
"shorts_lockup_cell.eml", // Part of 'shorts_shelf_carousel.eml'
|
||||
"video_card.eml" // Shorts that appear in a horizontal shelf.
|
||||
"modern_type_shelf_header_content.e",
|
||||
"shorts_lockup_cell.e", // Part of 'shorts_shelf_carousel.e'
|
||||
"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.
|
||||
*/
|
||||
private final StringTrieSearch exceptions = new StringTrieSearch(
|
||||
"metadata.eml",
|
||||
"thumbnail.eml",
|
||||
"avatar.eml",
|
||||
"overflow_button.eml"
|
||||
"metadata.e",
|
||||
"thumbnail.e",
|
||||
"avatar.e",
|
||||
"overflow_button.e"
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,18 +76,18 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
communityPosts = new StringFilterGroup(
|
||||
Settings.HIDE_COMMUNITY_POSTS,
|
||||
"post_base_wrapper", // may be obsolete and no longer needed.
|
||||
"text_post_root.eml",
|
||||
"images_post_root.eml",
|
||||
"images_post_slim.eml", // may be obsolete and no longer needed.
|
||||
"images_post_root_slim.eml",
|
||||
"text_post_root_slim.eml",
|
||||
"post_base_wrapper_slim.eml",
|
||||
"poll_post_root.eml",
|
||||
"videos_post_root.eml",
|
||||
"post_shelf_slim.eml",
|
||||
"videos_post_responsive_root.eml",
|
||||
"text_post_responsive_root.eml",
|
||||
"poll_post_responsive_root.eml"
|
||||
"text_post_root.e",
|
||||
"images_post_root.e",
|
||||
"images_post_slim.e", // may be obsolete and no longer needed.
|
||||
"images_post_root_slim.e",
|
||||
"text_post_root_slim.e",
|
||||
"post_base_wrapper_slim.e",
|
||||
"poll_post_root.e",
|
||||
"videos_post_root.e",
|
||||
"post_shelf_slim.e",
|
||||
"videos_post_responsive_root.e",
|
||||
"text_post_responsive_root.e",
|
||||
"poll_post_responsive_root.e"
|
||||
);
|
||||
|
||||
final var subscribersCommunityGuidelines = new StringFilterGroup(
|
||||
@@ -149,7 +149,7 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
|
||||
final var channelLinksPreview = new StringFilterGroup(
|
||||
Settings.HIDE_LINKS_PREVIEW,
|
||||
"attribution.eml"
|
||||
"attribution.e"
|
||||
);
|
||||
|
||||
final var emergencyBox = new StringFilterGroup(
|
||||
@@ -190,8 +190,8 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
|
||||
final var playables = new StringFilterGroup(
|
||||
Settings.HIDE_PLAYABLES,
|
||||
"horizontal_gaming_shelf.eml",
|
||||
"mini_game_card.eml"
|
||||
"horizontal_gaming_shelf.e",
|
||||
"mini_game_card.e"
|
||||
);
|
||||
|
||||
// Playable horizontal shelf header.
|
||||
@@ -228,7 +228,7 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
|
||||
compactChannelBarInnerButton = new StringFilterGroup(
|
||||
null,
|
||||
"|button.eml"
|
||||
"|button.e"
|
||||
);
|
||||
|
||||
joinMembershipButton = new ByteArrayFilterGroup(
|
||||
@@ -248,13 +248,13 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
|
||||
final var videoRecommendationLabels = new StringFilterGroup(
|
||||
Settings.HIDE_VIDEO_RECOMMENDATION_LABELS,
|
||||
"endorsement_header_footer.eml"
|
||||
"endorsement_header_footer.e"
|
||||
);
|
||||
|
||||
channelProfile = new StringFilterGroup(
|
||||
null,
|
||||
"channel_profile.eml",
|
||||
"page_header.eml"
|
||||
"channel_profile.e",
|
||||
"page_header.e"
|
||||
);
|
||||
channelProfileBuffer = new ByteArrayFilterGroupList();
|
||||
channelProfileBuffer.addAll(new ByteArrayFilterGroup(
|
||||
@@ -269,15 +269,15 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
|
||||
horizontalShelves = new StringFilterGroup(
|
||||
Settings.HIDE_HORIZONTAL_SHELVES,
|
||||
"horizontal_video_shelf.eml",
|
||||
"horizontal_shelf.eml",
|
||||
"horizontal_shelf_inline.eml",
|
||||
"horizontal_tile_shelf.eml"
|
||||
"horizontal_video_shelf.e",
|
||||
"horizontal_shelf.e",
|
||||
"horizontal_shelf_inline.e",
|
||||
"horizontal_tile_shelf.e"
|
||||
);
|
||||
|
||||
ticketShelf = new ByteArrayFilterGroup(
|
||||
Settings.HIDE_TICKET_SHELF,
|
||||
"ticket_item.eml"
|
||||
"ticket_item.e"
|
||||
);
|
||||
|
||||
addPathCallbacks(
|
||||
|
||||
@@ -24,13 +24,13 @@ public final class PlaybackSpeedMenuFilter extends Filter {
|
||||
// 0.05x litho speed menu.
|
||||
var playbackRateSelectorGroup = new StringFilterGroup(
|
||||
Settings.CUSTOM_SPEED_MENU,
|
||||
"playback_rate_selector_menu_sheet.eml-js"
|
||||
"playback_rate_selector_menu_sheet.e"
|
||||
);
|
||||
|
||||
// Old litho based speed menu.
|
||||
oldPlaybackMenuGroup = new StringFilterGroup(
|
||||
Settings.CUSTOM_SPEED_MENU,
|
||||
"playback_speed_sheet_content.eml-js");
|
||||
"playback_speed_sheet_content.e");
|
||||
|
||||
addPathCallbacks(playbackRateSelectorGroup, oldPlaybackMenuGroup);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||
|
||||
addPathCallbacks(
|
||||
videoQualityMenuFooter,
|
||||
new StringFilterGroup(null, "overflow_menu_item.eml")
|
||||
new StringFilterGroup(null, "overflow_menu_item.e")
|
||||
);
|
||||
|
||||
flyoutFilterGroupList.addAll(
|
||||
|
||||
@@ -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.
|
||||
// So must check for both buttons.
|
||||
addPathCallbacks(
|
||||
new StringFilterGroup(null, "|shorts_like_button.eml"),
|
||||
new StringFilterGroup(null, "|shorts_dislike_button.eml")
|
||||
new StringFilterGroup(null, "|shorts_like_button.e"),
|
||||
new StringFilterGroup(null, "|shorts_dislike_button.e")
|
||||
);
|
||||
|
||||
// After the button identifiers is binary data and then the video id for that specific short.
|
||||
|
||||
@@ -18,12 +18,12 @@ import app.revanced.extension.youtube.shared.PlayerType;
|
||||
@SuppressWarnings("unused")
|
||||
public final class ShortsFilter extends Filter {
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
@@ -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.
|
||||
shelfHeader = new StringFilterGroup(
|
||||
null,
|
||||
"shelf_header.eml"
|
||||
"shelf_header.e"
|
||||
);
|
||||
|
||||
addIdentifierCallbacks(shortsIdentifiers, shelfHeader);
|
||||
@@ -85,11 +85,11 @@ public final class ShortsFilter extends Filter {
|
||||
|
||||
shortsCompactFeedVideo = new StringFilterGroup(null,
|
||||
// Shorts that appear in the feed/search when the device is using tablet layout.
|
||||
"compact_video.eml",
|
||||
// 'video_lockup_with_attachment.eml' is shown instead of 'compact_video.eml' for some users
|
||||
"video_lockup_with_attachment.eml",
|
||||
"compact_video.e",
|
||||
// 'video_lockup_with_attachment.e' is shown instead of 'compact_video.e' for some users
|
||||
"video_lockup_with_attachment.e",
|
||||
// Search results that appear in a horizontal shelf.
|
||||
"video_card.eml");
|
||||
"video_card.e");
|
||||
|
||||
// Filter out items that use the 'frame0' thumbnail.
|
||||
// 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(
|
||||
Settings.HIDE_SHORTS_STICKERS,
|
||||
"stickers_layer.eml"
|
||||
"stickers_layer.e"
|
||||
);
|
||||
|
||||
StringFilterGroup likeFountain = new StringFilterGroup(
|
||||
Settings.HIDE_SHORTS_LIKE_FOUNTAIN,
|
||||
"like_fountain.eml"
|
||||
"like_fountain.e"
|
||||
);
|
||||
|
||||
StringFilterGroup likeButton = new StringFilterGroup(
|
||||
Settings.HIDE_SHORTS_LIKE_BUTTON,
|
||||
"shorts_like_button.eml",
|
||||
"reel_like_button.eml"
|
||||
"shorts_like_button.e",
|
||||
"reel_like_button.e"
|
||||
);
|
||||
|
||||
StringFilterGroup dislikeButton = new StringFilterGroup(
|
||||
Settings.HIDE_SHORTS_DISLIKE_BUTTON,
|
||||
"shorts_dislike_button.eml",
|
||||
"reel_dislike_button.eml"
|
||||
"shorts_dislike_button.e",
|
||||
"reel_dislike_button.e"
|
||||
);
|
||||
|
||||
StringFilterGroup previewComment = new StringFilterGroup(
|
||||
Settings.HIDE_SHORTS_PREVIEW_COMMENT,
|
||||
// Preview comment that can popup while a Short is playing.
|
||||
// Uses no bundled icons, and instead the users profile photo is shown.
|
||||
"participation_bar.eml"
|
||||
"participation_bar.e"
|
||||
);
|
||||
|
||||
joinButton = new StringFilterGroup(
|
||||
@@ -173,20 +173,20 @@ public final class ShortsFilter extends Filter {
|
||||
|
||||
paidPromotionButton = new StringFilterGroup(
|
||||
Settings.HIDE_PAID_PROMOTION_LABEL,
|
||||
"reel_player_disclosure.eml"
|
||||
"reel_player_disclosure.e"
|
||||
);
|
||||
|
||||
shortsActionBar = new StringFilterGroup(
|
||||
null,
|
||||
"shorts_action_bar.eml",
|
||||
"reel_action_bar.eml"
|
||||
"shorts_action_bar.e",
|
||||
"reel_action_bar.e"
|
||||
);
|
||||
|
||||
useSoundButton = new StringFilterGroup(
|
||||
Settings.HIDE_SHORTS_USE_SOUND_BUTTON,
|
||||
// First filter needed for "Use this sound" that can appear when viewing Shorts
|
||||
// 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.
|
||||
REEL_METAPANEL_PATH
|
||||
);
|
||||
@@ -209,13 +209,13 @@ public final class ShortsFilter extends Filter {
|
||||
|
||||
videoActionButton = new StringFilterGroup(
|
||||
null,
|
||||
// Can be simply 'button.eml', 'shorts_video_action_button.eml' or 'reel_action_button.eml'
|
||||
"button.eml"
|
||||
// Can be simply 'button.e', 'shorts_video_action_button.e' or 'reel_action_button.e'
|
||||
"button.e"
|
||||
);
|
||||
|
||||
suggestedAction = new StringFilterGroup(
|
||||
null,
|
||||
"suggested_action.eml"
|
||||
"suggested_action.e"
|
||||
);
|
||||
|
||||
addPathCallbacks(
|
||||
|
||||
@@ -8,38 +8,40 @@ import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.spoof.ClientType;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
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.
|
||||
*/
|
||||
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();
|
||||
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.of(
|
||||
ANDROID_VR_1_43_32,
|
||||
VISIONOS,
|
||||
ANDROID_CREATOR,
|
||||
ANDROID_VR_1_61_48,
|
||||
IPADOS)
|
||||
: List.of(
|
||||
ANDROID_VR_1_61_48,
|
||||
VISIONOS,
|
||||
List<ClientType> availableClients = List.of(
|
||||
ANDROID_CREATOR,
|
||||
ANDROID_VR_1_43_32,
|
||||
IPADOS
|
||||
);
|
||||
VISIONOS,
|
||||
IPADOS);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
availableClients, client);
|
||||
|
||||
@@ -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.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
||||
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.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
|
||||
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 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_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_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);
|
||||
@@ -75,9 +77,6 @@ public class Settings extends BaseSettings {
|
||||
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);
|
||||
|
||||
// Audio
|
||||
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
|
||||
|
||||
// Ads
|
||||
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);
|
||||
@@ -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 SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
|
||||
"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,
|
||||
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
|
||||
|
||||
@@ -526,6 +527,11 @@ public class Settings extends BaseSettings {
|
||||
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
|
||||
// a "revanced_" on the old setting causes duplicate key exceptions during export.
|
||||
SharedPrefCategory revancedPrefs = Setting.preferences;
|
||||
|
||||
@@ -83,12 +83,13 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
|
||||
String summary = str("revanced_spoof_video_streams_about_no_audio_tracks");
|
||||
|
||||
switch (clientType) {
|
||||
case ANDROID_VR_1_61_48 ->
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
|
||||
case ANDROID_CREATOR ->
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
|
||||
summary += '\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");
|
||||
// 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 ->
|
||||
summary = str("revanced_spoof_video_streams_about_playback_failure")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
|
||||
|
||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
||||
org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
version = 5.42.0-dev.7
|
||||
version = 5.42.2-dev.3
|
||||
|
||||
@@ -10,7 +10,7 @@ annotation = "1.9.1"
|
||||
appcompat = "1.7.0"
|
||||
okhttp = "5.0.0-alpha.14"
|
||||
retrofit = "2.11.0"
|
||||
guava = "33.4.0-jre"
|
||||
guava = "33.5.0-jre"
|
||||
protobuf-javalite = "4.32.0"
|
||||
protoc = "4.32.0"
|
||||
protobuf = "0.9.5"
|
||||
|
||||
42
package-lock.json
generated
42
package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.10.1",
|
||||
"semantic-release": "^24.2.7"
|
||||
"semantic-release": "^24.2.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
@@ -6889,9 +6889,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semantic-release": {
|
||||
"version": "24.2.7",
|
||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.7.tgz",
|
||||
"integrity": "sha512-g7RssbTAbir1k/S7uSwSVZFfFXwpomUB9Oas0+xi9KStSCmeDXcA7rNhiskjLqvUe/Evhx8fVCT16OSa34eM5g==",
|
||||
"version": "24.2.9",
|
||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz",
|
||||
"integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -6909,7 +6909,7 @@
|
||||
"find-versions": "^6.0.0",
|
||||
"get-stream": "^6.0.0",
|
||||
"git-log-parser": "^1.2.0",
|
||||
"hook-std": "^3.0.0",
|
||||
"hook-std": "^4.0.0",
|
||||
"hosted-git-info": "^8.0.0",
|
||||
"import-from-esm": "^2.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
@@ -6921,7 +6921,7 @@
|
||||
"read-package-up": "^11.0.0",
|
||||
"resolve-from": "^5.0.0",
|
||||
"semver": "^7.3.2",
|
||||
"semver-diff": "^4.0.0",
|
||||
"semver-diff": "^5.0.0",
|
||||
"signale": "^1.2.1",
|
||||
"yargs": "^17.5.1"
|
||||
},
|
||||
@@ -7045,6 +7045,19 @@
|
||||
"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": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
|
||||
@@ -7138,6 +7151,23 @@
|
||||
"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": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.10.1",
|
||||
"semantic-release": "^24.2.7"
|
||||
"semantic-release": "^24.2.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +280,10 @@ public final class app/revanced/patches/instagram/hide/stories/HideStoriesKt {
|
||||
public static final fun getHideStoriesPatch ()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 static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -288,6 +292,14 @@ public final class app/revanced/patches/instagram/misc/links/OpenLinksExternally
|
||||
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 static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -459,9 +471,14 @@ public final class app/revanced/patches/music/misc/spoof/UserAgentClientSpoofPat
|
||||
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 static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
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_15_or_greater ()Z
|
||||
}
|
||||
@@ -1005,11 +1022,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 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 static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
@@ -1907,6 +1919,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 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 removeFromParent (Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
|
||||
}
|
||||
|
||||
public final class app/revanced/util/resource/ArrayResource : app/revanced/util/resource/BaseResource {
|
||||
|
||||
@@ -2,11 +2,13 @@ package app.revanced.patches.finanzonline.detection.root
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
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")
|
||||
val rootDetectionPatch = bytecodePatch(
|
||||
name = "Remove root detection",
|
||||
description = "Removes the check for root permissions.",
|
||||
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
|
||||
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION,
|
||||
) {
|
||||
compatibleWith("at.gv.bmf.bmf2go")
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package app.revanced.patches.idaustria.detection.root
|
||||
|
||||
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
|
||||
|
||||
@Suppress("unused")
|
||||
val rootDetectionPatch = bytecodePatch(
|
||||
name = "Remove root detection",
|
||||
description = "Removes the check for root permissions and unlocked bootloader.",
|
||||
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
|
||||
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
|
||||
) {
|
||||
compatibleWith("at.gv.oe.app")
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" }
|
||||
}
|
||||
@@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
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
|
||||
@@ -50,26 +55,21 @@ private val disableSplashAnimationPatch = bytecodePatch {
|
||||
}
|
||||
}
|
||||
|
||||
private const val APP_NAME = "YT Music ReVanced"
|
||||
|
||||
@Suppress("unused")
|
||||
val customBrandingPatch = baseCustomBrandingPatch(
|
||||
defaultAppName = APP_NAME,
|
||||
appNameValues = mapOf(
|
||||
"YT Music ReVanced" to APP_NAME,
|
||||
"Music ReVanced" to "Music ReVanced",
|
||||
"Music" to "Music",
|
||||
"YT Music" to "YT Music",
|
||||
),
|
||||
resourceFolder = "custom-branding/music",
|
||||
iconResourceFileNames = arrayOf(
|
||||
"adaptiveproduct_youtube_music_2024_q4_background_color_108",
|
||||
"adaptiveproduct_youtube_music_2024_q4_foreground_color_108",
|
||||
"ic_launcher_release",
|
||||
),
|
||||
addResourcePatchName = "music",
|
||||
originalLauncherIconName = "ic_launcher_release",
|
||||
originalAppName = "@string/app_launcher_name",
|
||||
originalAppPackageName = MUSIC_PACKAGE_NAME,
|
||||
copyExistingIntentsToAliases = false,
|
||||
numberOfPresetAppNames = 5,
|
||||
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
|
||||
mainActivityName = MUSIC_MAIN_ACTIVITY_NAME,
|
||||
activityAliasNameWithIntents = MUSIC_MAIN_ACTIVITY_NAME,
|
||||
preferenceScreen = PreferenceScreen.GENERAL,
|
||||
|
||||
block = {
|
||||
dependsOn(disableSplashAnimationPatch)
|
||||
dependsOn(sharedExtensionPatch, disableSplashAnimationPatch)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.apps.youtube.music"(
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package app.revanced.patches.music.misc.gms
|
||||
|
||||
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 MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.addResourcesPatch
|
||||
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.spoof.spoofVideoStreamsPatch
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
|
||||
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
fixMediaFetchHotConfigChanges = { true },
|
||||
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
|
||||
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
|
||||
fixMediaFetchHotConfig = { true },
|
||||
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
|
||||
|
||||
block = {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
@@ -38,6 +38,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
executeBlock = {
|
||||
addResources("music", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
|
||||
@@ -51,10 +52,5 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
musicActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
@@ -7,6 +7,8 @@ import app.revanced.util.findPlayStoreServicesVersion
|
||||
|
||||
var is_7_33_or_greater = false
|
||||
private set
|
||||
var is_8_10_or_greater = false
|
||||
private set
|
||||
var is_8_11_or_greater = false
|
||||
private set
|
||||
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.
|
||||
is_7_33_or_greater = 245199000 <= playStoreServicesVersion
|
||||
is_8_10_or_greater = 244799000 <= playStoreServicesVersion
|
||||
is_8_11_or_greater = 251199000 <= playStoreServicesVersion
|
||||
is_8_15_or_greater = 251530000 <= playStoreServicesVersion
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package app.revanced.patches.orfon.detection.root
|
||||
|
||||
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
|
||||
|
||||
@Suppress("unused")
|
||||
val removeRootDetectionPatch = bytecodePatch(
|
||||
name = "Remove root detection",
|
||||
description = "Removes the check for root permissions.",
|
||||
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
|
||||
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
|
||||
) {
|
||||
compatibleWith("com.nousguide.android.orftvthek")
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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.patches.reddit.customclients.CREATE_NEW_CLIENT_METHOD
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.misc.extension.sharedExtensionPatch
|
||||
@@ -27,9 +26,7 @@ val fixRedgifsApi = fixRedgifsApiPatch(
|
||||
}
|
||||
replaceInstruction(
|
||||
index,
|
||||
"""
|
||||
invoke-static { }, ${EXTENSION_CLASS_DESCRIPTOR}->$CREATE_NEW_CLIENT_METHOD
|
||||
"""
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->$CREATE_NEW_CLIENT_METHOD"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@ package app.revanced.patches.reddit.misc.tracking.url
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
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")
|
||||
val sanitizeUrlQueryPatch = bytecodePatch(
|
||||
name = "Sanitize sharing links",
|
||||
description = "Removes (tracking) query parameters from the URLs when sharing links.",
|
||||
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||
) {
|
||||
compatibleWith("com.reddit.frontpage")
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@ package app.revanced.patches.serviceportalbund.detection.root
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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")
|
||||
val rootDetectionPatch = bytecodePatch(
|
||||
name = "Remove root detection",
|
||||
description = "Removes the check for root permissions and unlocked bootloader.",
|
||||
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
|
||||
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
|
||||
) {
|
||||
compatibleWith("at.gv.bka.serviceportal")
|
||||
|
||||
|
||||
@@ -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."
|
||||
@@ -1,146 +1,397 @@
|
||||
package app.revanced.patches.shared.layout.branding
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.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.copyResources
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.removeFromParent
|
||||
import app.revanced.util.returnEarly
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.NodeList
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.util.logging.Logger
|
||||
|
||||
private const val REVANCED_ICON = "ReVanced*Logo" // Can never be a valid path.
|
||||
private val mipmapDirectories = arrayOf(
|
||||
// Target app does not have ldpi icons.
|
||||
"mipmap-mdpi",
|
||||
"mipmap-hdpi",
|
||||
"mipmap-xhdpi",
|
||||
"mipmap-xxhdpi",
|
||||
"mipmap-xxxhdpi"
|
||||
)
|
||||
|
||||
internal val mipmapDirectories = arrayOf(
|
||||
"xxxhdpi",
|
||||
"xxhdpi",
|
||||
"xhdpi",
|
||||
"hdpi",
|
||||
"mdpi",
|
||||
).map { "mipmap-$it" }.toTypedArray()
|
||||
private val iconStyleNames = arrayOf(
|
||||
"rounded",
|
||||
"minimal",
|
||||
"scaled"
|
||||
)
|
||||
|
||||
private fun formatResourceFileList(resourceNames: Array<String>) = resourceNames.joinToString("\n") { "- $it" }
|
||||
private const val ORIGINAL_USER_ICON_STYLE_NAME = "original"
|
||||
private const val CUSTOM_USER_ICON_STYLE_NAME = "custom"
|
||||
|
||||
/**
|
||||
* Attempts to fix unescaped and invalid characters not allowed for an Android app name.
|
||||
*/
|
||||
private fun escapeAppName(name: String): String? {
|
||||
// Remove ASCII control characters.
|
||||
val cleanedName = name.filter { it.code >= 32 }
|
||||
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_"
|
||||
|
||||
// Replace invalid XML characters with escaped equivalents.
|
||||
val escapedName = cleanedName
|
||||
.replace("&", "&") // Must be first to avoid double-escaping.
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace(Regex("(?<!&)\""), """)
|
||||
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"
|
||||
)
|
||||
|
||||
// Trim empty spacing.
|
||||
val trimmed = escapedName.trim()
|
||||
private const val USER_CUSTOM_MONOCHROME_NAME = "$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml"
|
||||
|
||||
return trimmed.ifBlank { null }
|
||||
}
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/patches/CustomBrandingPatch;"
|
||||
|
||||
/**
|
||||
* Shared custom branding patch for YouTube and YT Music.
|
||||
*/
|
||||
internal fun baseCustomBrandingPatch(
|
||||
defaultAppName: String,
|
||||
appNameValues: Map<String, String>,
|
||||
resourceFolder: String,
|
||||
iconResourceFileNames: Array<String>,
|
||||
block: ResourcePatchBuilder.() -> Unit = {},
|
||||
addResourcePatchName: String,
|
||||
originalLauncherIconName: String,
|
||||
originalAppName: String,
|
||||
originalAppPackageName: String,
|
||||
copyExistingIntentsToAliases: Boolean,
|
||||
numberOfPresetAppNames: Int,
|
||||
mainActivityOnCreateFingerprint: Fingerprint,
|
||||
mainActivityName: String,
|
||||
activityAliasNameWithIntents: String,
|
||||
preferenceScreen: BasePreferenceScreen.Screen,
|
||||
block: ResourcePatchBuilder.() -> Unit,
|
||||
executeBlock: ResourcePatchContext.() -> Unit = {}
|
||||
): ResourcePatch = resourcePatch(
|
||||
name = "Custom branding",
|
||||
description = "Applies a custom app name and icon. Defaults to \"$defaultAppName\" and the ReVanced logo.",
|
||||
use = false,
|
||||
description = "Adds options to change the app icon and app name. " +
|
||||
"Branding cannot be changed for mounted (root) installations."
|
||||
) {
|
||||
val iconResourceFileNamesPng = iconResourceFileNames.map { "$it.png" }.toTypedArray<String>()
|
||||
|
||||
val appName by stringOption(
|
||||
key = "appName",
|
||||
default = defaultAppName,
|
||||
values = appNameValues,
|
||||
val customName by stringOption(
|
||||
key = "customName",
|
||||
title = "App name",
|
||||
description = "The name of the app.",
|
||||
description = "Custom app name."
|
||||
)
|
||||
|
||||
val iconPath by stringOption(
|
||||
key = "iconPath",
|
||||
default = REVANCED_ICON,
|
||||
values = mapOf("ReVanced Logo" to REVANCED_ICON),
|
||||
title = "App icon",
|
||||
val customIcon by stringOption(
|
||||
key = "customIcon",
|
||||
title = "Custom icon",
|
||||
description = """
|
||||
The icon to apply to the app.
|
||||
Folder with images to use as a custom icon.
|
||||
|
||||
If a path to a folder is provided, the folder must contain the following folders:
|
||||
|
||||
${formatResourceFileList(mipmapDirectories)}
|
||||
|
||||
Each of these folders must contain the following files:
|
||||
|
||||
${formatResourceFileList(iconResourceFileNamesPng)}
|
||||
""".trimIndentMultiline(),
|
||||
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 can contain a 'drawable' folder with the monochrome icon file:
|
||||
$USER_CUSTOM_MONOCHROME_NAME
|
||||
""".trimIndentMultiline()
|
||||
)
|
||||
|
||||
block()
|
||||
|
||||
dependsOn(
|
||||
addResourcesPatch,
|
||||
|
||||
bytecodePatch {
|
||||
execute {
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setBranding()V"
|
||||
)
|
||||
|
||||
numberOfPresetAppNamesExtensionFingerprint.method.returnEarly(numberOfPresetAppNames)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
finalize {
|
||||
val useCustomName = customName != null
|
||||
val useCustomIcon = customIcon != null
|
||||
|
||||
if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) {
|
||||
if (useCustomName || useCustomIcon) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Custom branding does not work with root installation. No changes applied."
|
||||
)
|
||||
}
|
||||
return@finalize
|
||||
}
|
||||
|
||||
preferenceScreen.addPreferences(
|
||||
if (useCustomName) {
|
||||
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 (useCustomIcon) {
|
||||
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")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
execute {
|
||||
// Change the app icon and launch screen.
|
||||
val iconResourceGroups = mipmapDirectories.map { directory ->
|
||||
ResourceGroup(
|
||||
directory,
|
||||
*iconResourceFileNamesPng,
|
||||
addResources("shared", "layout.branding.baseCustomBrandingPatch")
|
||||
addResources(addResourcePatchName, "layout.branding.customBrandingPatch")
|
||||
|
||||
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"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val iconPathTrimmed = iconPath!!.trim()
|
||||
if (iconPathTrimmed == REVANCED_ICON) {
|
||||
iconResourceGroups.forEach {
|
||||
copyResources(resourceFolder, it)
|
||||
}
|
||||
} else {
|
||||
val filePath = File(iconPathTrimmed)
|
||||
val resourceDirectory = get("res")
|
||||
// Copy template user icon, because the aliases must be added even if no user icon is provided.
|
||||
copyResources(
|
||||
"custom-branding",
|
||||
ResourceGroup(
|
||||
"mipmap-anydpi",
|
||||
"$LAUNCHER_RESOURCE_NAME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml",
|
||||
),
|
||||
ResourceGroup(
|
||||
"drawable",
|
||||
"$LAUNCHER_ADAPTIVE_MONOCHROME_PREFIX$CUSTOM_USER_ICON_STYLE_NAME.xml",
|
||||
)
|
||||
)
|
||||
|
||||
iconResourceGroups.forEach { group ->
|
||||
val fromDirectory = filePath.resolve(group.resourceDirectoryName)
|
||||
val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName)
|
||||
|
||||
group.resources.forEach { iconFileName ->
|
||||
Files.write(
|
||||
toDirectory.resolve(iconFileName).toPath(),
|
||||
fromDirectory.resolve(iconFileName).readBytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
// Copy template icon png 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",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Change the app name.
|
||||
escapeAppName(appName!!)?.let { escapedAppName ->
|
||||
val newValue = "android:label=\"$escapedAppName\""
|
||||
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)
|
||||
|
||||
val manifest = get("AndroidManifest.xml")
|
||||
val original = manifest.readText()
|
||||
val replacement = original
|
||||
// YouTube
|
||||
.replace("android:label=\"@string/application_name\"", newValue)
|
||||
// YT Music
|
||||
.replace("android:label=\"@string/app_launcher_name\"", newValue)
|
||||
// Copy all intents from the original alias so long press actions still work.
|
||||
if (copyExistingIntentsToAliases) {
|
||||
for (i in 0 until intents.length) {
|
||||
alias.appendChild(
|
||||
intents.item(i).cloneNode(true)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val intentFilter = document.createElement("intent-filter").apply {
|
||||
val action = document.createElement("action")
|
||||
action.setAttribute("android:name", "android.intent.action.MAIN")
|
||||
appendChild(action)
|
||||
|
||||
if (original == replacement) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Could not replace manifest app name"
|
||||
val category = document.createElement("category")
|
||||
category.setAttribute("android:name", "android.intent.category.LAUNCHER")
|
||||
appendChild(category)
|
||||
}
|
||||
alias.appendChild(intentFilter)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
manifest.writeText(replacement)
|
||||
// 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()
|
||||
}
|
||||
|
||||
executeBlock() // Must be after the main code to rename the new icons for YouTube 19.34+.
|
||||
// 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 if it provided.
|
||||
val monochromeRelativePath = "drawable/$USER_CUSTOM_MONOCHROME_NAME"
|
||||
val monochromeFile = iconPathFile.resolve(monochromeRelativePath)
|
||||
if (monochromeFile.exists()) {
|
||||
monochromeFile.copyTo(
|
||||
target = resourceDirectory.resolve(monochromeRelativePath),
|
||||
overwrite = true
|
||||
)
|
||||
copiedFiles = true
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("Could not find any replacement images in " +
|
||||
"patch option path: " + iconPathFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
executeBlock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ internal val darkThemeBackgroundColorOption = stringOption(
|
||||
*/
|
||||
internal fun baseThemePatch(
|
||||
extensionClassDescriptor: String,
|
||||
block: BytecodePatchBuilder.() -> Unit = {},
|
||||
block: BytecodePatchBuilder.() -> Unit,
|
||||
executeBlock: BytecodePatchContext.() -> Unit = {}
|
||||
) = bytecodePatch(
|
||||
name = "Theme",
|
||||
|
||||
@@ -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.util.containsLiteralInstruction
|
||||
@@ -7,10 +7,14 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
||||
internal val formatStreamModelToStringFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("Ljava/lang/String;")
|
||||
custom { method, classDef ->
|
||||
method.name == "toString" && classDef.type ==
|
||||
"Lcom/google/android/libraries/youtube/innertube/model/media/FormatStreamModel;"
|
||||
custom { method, _ ->
|
||||
method.name == "toString"
|
||||
}
|
||||
strings(
|
||||
// Strings are partial matches.
|
||||
"isDefaultAudioTrack=",
|
||||
"audioTrackId="
|
||||
)
|
||||
}
|
||||
|
||||
internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L
|
||||
@@ -20,7 +24,6 @@ internal val selectAudioStreamFingerprint = fingerprint {
|
||||
returns("L")
|
||||
custom { method, _ ->
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
package app.revanced.patches.shared.misc.gms
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patches.shared.misc.gms.EXTENSION_CLASS_DESCRIPTOR
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
const val GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME = "getGmsCoreVendorGroupId"
|
||||
|
||||
internal val gmsCoreSupportFingerprint = fingerprint {
|
||||
custom { _, classDef ->
|
||||
classDef.endsWith("GmsCoreSupport;")
|
||||
}
|
||||
}
|
||||
|
||||
internal val googlePlayUtilityFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returns("I")
|
||||
@@ -28,3 +23,21 @@ internal val serviceCheckFingerprint = fingerprint {
|
||||
parameters("L", "I")
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package app.revanced.patches.shared.misc.gms
|
||||
|
||||
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.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.setOrGetFallbackPackageName
|
||||
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.AUTHORITIES
|
||||
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.builder.instruction.BuilderInstruction21c
|
||||
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.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*)+\$"
|
||||
|
||||
/**
|
||||
@@ -201,19 +212,18 @@ fun gmsCoreSupportPatch(
|
||||
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.
|
||||
mainActivityOnCreateFingerprint.method.apply {
|
||||
addInstructions(
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, Lapp/revanced/extension/shared/GmsCoreSupport;->" +
|
||||
"checkGmsCore(Landroid/app/Activity;)V",
|
||||
)
|
||||
}
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"checkGmsCore(Landroid/app/Activity;)V"
|
||||
)
|
||||
|
||||
// Change the vendor of GmsCore in the extension.
|
||||
gmsCoreSupportFingerprint.classDef.methods
|
||||
.single { it.name == GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME }
|
||||
.replaceInstruction(0, "const-string v0, \"$gmsCoreVendorGroupId\"")
|
||||
gmsCoreSupportFingerprint.method.returnEarly(gmsCoreVendorGroupId!!)
|
||||
|
||||
executeBlock()
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
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.PreferenceCategory
|
||||
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 =
|
||||
"Lapp/revanced/extension/shared/patches/SanitizeSharingLinksPatch;"
|
||||
|
||||
/**
|
||||
* Patch shared by YouTube and YT Music.
|
||||
*/
|
||||
internal fun sanitizeSharingLinksPatch(
|
||||
block: BytecodePatchBuilder.() -> Unit = {},
|
||||
executeBlock: BytecodePatchContext.() -> Unit = {},
|
||||
preferenceScreen: BasePreferenceScreen.Screen,
|
||||
replaceMusicLinksWithYouTube: Boolean = false
|
||||
) = bytecodePatch(
|
||||
name = "Sanitize sharing links",
|
||||
description = "Adds an option to remove the tracking query parameter from shared links.",
|
||||
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||
) {
|
||||
block()
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
@@ -36,11 +37,13 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
private lateinit var buildRequestMethod: MutableMethod
|
||||
private var buildRequestMethodUrlRegister = -1
|
||||
|
||||
fun spoofVideoStreamsPatch(
|
||||
block: BytecodePatchBuilder.() -> Unit = {},
|
||||
fixMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
|
||||
fixMediaFetchHotConfigAlternativeChanges: BytecodePatchBuilder.() -> Boolean = { false },
|
||||
internal fun spoofVideoStreamsPatch(
|
||||
extensionClassDescriptor: String,
|
||||
mainActivityOnCreateFingerprint: Fingerprint,
|
||||
fixMediaFetchHotConfig: BytecodePatchBuilder.() -> Boolean = { false },
|
||||
fixMediaFetchHotConfigAlternative: BytecodePatchBuilder.() -> Boolean = { false },
|
||||
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
|
||||
block: BytecodePatchBuilder.() -> Unit,
|
||||
executeBlock: BytecodePatchContext.() -> Unit = {},
|
||||
) = bytecodePatch(
|
||||
name = "Spoof video streams",
|
||||
@@ -53,6 +56,11 @@ fun spoofVideoStreamsPatch(
|
||||
execute {
|
||||
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $extensionClassDescriptor->setClientOrderToUse()V"
|
||||
)
|
||||
|
||||
// region Enable extension helper method used by other patches
|
||||
|
||||
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
|
||||
@@ -308,14 +316,14 @@ fun spoofVideoStreamsPatch(
|
||||
|
||||
// region turn off stream config replacement feature flag.
|
||||
|
||||
if (fixMediaFetchHotConfigChanges()) {
|
||||
if (fixMediaFetchHotConfig()) {
|
||||
mediaFetchHotConfigFingerprint.method.insertLiteralOverride(
|
||||
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
|
||||
)
|
||||
}
|
||||
|
||||
if (fixMediaFetchHotConfigAlternativeChanges()) {
|
||||
if (fixMediaFetchHotConfigAlternative()) {
|
||||
mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride(
|
||||
MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG,
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
|
||||
|
||||
@@ -17,7 +17,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
@Suppress("unused")
|
||||
val hideCreateButtonPatch = bytecodePatch(
|
||||
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")
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package app.revanced.patches.spotify.misc.privacy
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
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.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
@@ -15,8 +17,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
|
||||
@Suppress("unused")
|
||||
val sanitizeSharingLinksPatch = bytecodePatch(
|
||||
name = "Sanitize sharing links",
|
||||
description = "Removes the tracking query parameters from links before they are shared.",
|
||||
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||
) {
|
||||
compatibleWith("com.spotify.music")
|
||||
|
||||
@@ -24,7 +26,7 @@ val sanitizeSharingLinksPatch = bytecodePatch(
|
||||
|
||||
execute {
|
||||
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) {
|
||||
shareCopyUrlFingerprint
|
||||
|
||||
@@ -1,36 +1,64 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
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.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
|
||||
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
|
||||
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.returnEarly
|
||||
import java.net.InetAddress
|
||||
import java.net.UnknownHostException
|
||||
import java.util.logging.Logger
|
||||
|
||||
internal var tweetShareLinkTemplateId = -1L
|
||||
private set
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;"
|
||||
|
||||
internal val domainNameOption by stringOption(
|
||||
key = "domainName",
|
||||
default = "https://fxtwitter.com",
|
||||
title = "Domain name",
|
||||
description = "The domain name to use when sharing links.",
|
||||
required = true,
|
||||
) {
|
||||
// Do a courtesy check if the host can be resolved.
|
||||
// If it does not resolve, then print a warning but use the host anyway.
|
||||
// Unresolvable hosts should not be rejected, since the patching environment
|
||||
// may not allow network connections or the network may be down.
|
||||
try {
|
||||
InetAddress.getByName(it)
|
||||
} catch (e: UnknownHostException) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"Host \"$it\" did not resolve to any domain."
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
internal val changeLinkSharingDomainResourcePatch = resourcePatch {
|
||||
dependsOn(resourceMappingPatch)
|
||||
|
||||
execute {
|
||||
tweetShareLinkTemplateId = resourceMappings["string", "tweet_share_link"]
|
||||
val domainName = domainNameOption!!
|
||||
|
||||
val shareLinkTemplate = if (domainName.endsWith("/")) {
|
||||
"$domainName%1\$s/status/%2\$s"
|
||||
} else {
|
||||
"$domainName/%1\$s/status/%2\$s"
|
||||
}
|
||||
|
||||
document("res/values/strings.xml").use { document ->
|
||||
document.documentElement.childNodes.findElementByAttributeValueOrThrow(
|
||||
"name",
|
||||
"tweet_share_link"
|
||||
).textContent = shareLinkTemplate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
name = "Change link sharing domain",
|
||||
description = "Replaces the domain name of Twitter links when sharing them.",
|
||||
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
|
||||
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
|
||||
) {
|
||||
dependsOn(
|
||||
changeLinkSharingDomainResourcePatch,
|
||||
@@ -44,26 +72,11 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
)
|
||||
)
|
||||
|
||||
val domainName by stringOption(
|
||||
key = "domainName",
|
||||
default = "fxtwitter.com",
|
||||
title = "Domain name",
|
||||
description = "The domain name to use when sharing links.",
|
||||
required = true,
|
||||
)
|
||||
|
||||
execute {
|
||||
linkSharingDomainFingerprint.let {
|
||||
val replacementIndex = it.stringMatches!!.first().index
|
||||
val domainRegister = it.method.getInstruction<OneRegisterInstruction>(
|
||||
replacementIndex
|
||||
).registerA
|
||||
val domainName = domainNameOption!!
|
||||
|
||||
it.method.replaceInstruction(
|
||||
replacementIndex,
|
||||
"const-string v$domainRegister, \"https://$domainName\"",
|
||||
)
|
||||
}
|
||||
// Replace the domain name in the link sharing extension methods.
|
||||
linkSharingDomainHelperFingerprint.method.returnEarly(domainName)
|
||||
|
||||
// Replace the domain name when copying a link with "Copy link" button.
|
||||
linkBuilderFingerprint.method.addInstructions(
|
||||
@@ -74,20 +87,5 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
return-object p0
|
||||
"""
|
||||
)
|
||||
|
||||
// Used in the Share via... dialog.
|
||||
linkResourceGetterFingerprint.method.apply {
|
||||
val templateIdConstIndex = indexOfFirstLiteralInstructionOrThrow(tweetShareLinkTemplateId)
|
||||
|
||||
// Format the link with the new domain name register (1 instruction below the const).
|
||||
val formatLinkCallIndex = templateIdConstIndex + 1
|
||||
val register = getInstruction<FiveRegisterInstruction>(formatLinkCallIndex).registerE
|
||||
|
||||
// Replace the original method call with the new method call.
|
||||
replaceInstruction(
|
||||
formatLinkCallIndex,
|
||||
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->formatResourceLink([Ljava/lang/Object;)Ljava/lang/String;",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.literal
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val openLinkFingerprint = fingerprint {
|
||||
returns("V")
|
||||
@@ -19,13 +17,8 @@ internal val linkBuilderFingerprint = fingerprint {
|
||||
strings("/%1\$s/status/%2\$d")
|
||||
}
|
||||
|
||||
// Gets Resource string for share link view available by pressing "Share via" button.
|
||||
internal val linkResourceGetterFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Landroid/content/res/Resources;")
|
||||
literal { tweetShareLinkTemplateId }
|
||||
}
|
||||
|
||||
internal val linkSharingDomainFingerprint = fingerprint {
|
||||
strings("https://fxtwitter.com")
|
||||
internal val linkSharingDomainHelperFingerprint = fingerprint {
|
||||
custom { method, classDef ->
|
||||
method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
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")
|
||||
val sanitizeSharingLinksPatch = bytecodePatch(
|
||||
name = "Sanitize sharing links",
|
||||
description = "Removes the tracking query parameters from links before they are shared.",
|
||||
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||
) {
|
||||
compatibleWith(
|
||||
"com.twitter.android"(
|
||||
|
||||
@@ -1,34 +1,28 @@
|
||||
package app.revanced.patches.youtube.layout.branding
|
||||
|
||||
import app.revanced.patches.shared.layout.branding.baseCustomBrandingPatch
|
||||
import app.revanced.patches.shared.layout.branding.mipmapDirectories
|
||||
import java.nio.file.Files
|
||||
|
||||
private const val APP_NAME = "YouTube ReVanced"
|
||||
|
||||
private val youtubeIconResourceFileNames_19_34 = mapOf(
|
||||
"adaptiveproduct_youtube_foreground_color_108" to "adaptiveproduct_youtube_2024_q4_foreground_color_108",
|
||||
"adaptiveproduct_youtube_background_color_108" to "adaptiveproduct_youtube_2024_q4_background_color_108",
|
||||
)
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_MAIN_ACTIVITY_NAME
|
||||
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
val customBrandingPatch = baseCustomBrandingPatch(
|
||||
defaultAppName = APP_NAME,
|
||||
appNameValues = mapOf(
|
||||
"YouTube ReVanced" to APP_NAME,
|
||||
"YT ReVanced" to "YT ReVanced",
|
||||
"YT" to "YT",
|
||||
"YouTube" to "YouTube",
|
||||
),
|
||||
resourceFolder = "custom-branding/youtube",
|
||||
iconResourceFileNames = arrayOf(
|
||||
"adaptiveproduct_youtube_background_color_108",
|
||||
"adaptiveproduct_youtube_foreground_color_108",
|
||||
"ic_launcher",
|
||||
"ic_launcher_round",
|
||||
),
|
||||
addResourcePatchName = "youtube",
|
||||
originalLauncherIconName = "ic_launcher",
|
||||
originalAppName = "@string/application_name",
|
||||
originalAppPackageName = YOUTUBE_PACKAGE_NAME,
|
||||
copyExistingIntentsToAliases = true,
|
||||
numberOfPresetAppNames = 5,
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
mainActivityName = YOUTUBE_MAIN_ACTIVITY_NAME,
|
||||
activityAliasNameWithIntents = "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity",
|
||||
preferenceScreen = PreferenceScreen.GENERAL_LAYOUT,
|
||||
|
||||
block = {
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
@@ -37,20 +31,5 @@ val customBrandingPatch = baseCustomBrandingPatch(
|
||||
"20.14.43",
|
||||
)
|
||||
)
|
||||
},
|
||||
|
||||
executeBlock = {
|
||||
val resourceDirectory = get("res")
|
||||
|
||||
mipmapDirectories.forEach { directory ->
|
||||
val targetDirectory = resourceDirectory.resolve(directory)
|
||||
|
||||
youtubeIconResourceFileNames_19_34.forEach { (old, new) ->
|
||||
val oldFile = targetDirectory.resolve("$old.png")
|
||||
val newFile = targetDirectory.resolve("$new.png")
|
||||
|
||||
Files.write(newFile.toPath(), oldFile.readBytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -136,8 +136,21 @@ val changeHeaderPatch = resourcePatch(
|
||||
)
|
||||
|
||||
if (custom != null) {
|
||||
val sourceFolders = File(custom!!).listFiles { file -> file.isDirectory }
|
||||
?: throw PatchException("The provided path is not a directory: $custom")
|
||||
val customFile = File(custom!!)
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException("The custom icon path cannot be found: " +
|
||||
customFile.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException("The custom icon path must be a folder: "
|
||||
+ customFile.absolutePath)
|
||||
}
|
||||
|
||||
val sourceFolders = customFile.listFiles { file -> file.isDirectory }
|
||||
?: throw PatchException("The custom icon path contains no subfolders: " +
|
||||
customFile.absolutePath)
|
||||
|
||||
val customResourceFileNames = getLightDarkFileNames(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
|
||||
@@ -166,7 +179,8 @@ val changeHeaderPatch = resourcePatch(
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("No custom header images found in the provided path: $custom")
|
||||
throw PatchException("No custom header images found in " +
|
||||
"the provided path: " + customFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import app.revanced.util.forEachLiteralValueInstruction
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstLiteralInstruction
|
||||
import app.revanced.util.removeFromParent
|
||||
import app.revanced.util.returnLate
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
@@ -127,7 +128,7 @@ private val hideShortsComponentsResourcePatch = resourcePatch {
|
||||
)
|
||||
|
||||
if (hideShortsAppShortcut == true) {
|
||||
shortsItem.parentNode.removeChild(shortsItem)
|
||||
shortsItem.removeFromParent()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +139,7 @@ private val hideShortsComponentsResourcePatch = resourcePatch {
|
||||
)
|
||||
|
||||
if (hideShortsWidget == true) {
|
||||
shortsItem.parentNode.removeChild(shortsItem)
|
||||
shortsItem.removeFromParent()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
|
||||
addInstructions(
|
||||
index + 1,
|
||||
"""
|
||||
invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->overrideBackPressToExit(Z)Z
|
||||
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->overrideBackPressToExit(Z)Z
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package app.revanced.patches.youtube.misc.gms
|
||||
|
||||
internal object Constants {
|
||||
internal const val YOUTUBE_MAIN_ACTIVITY_NAME = "com.google.android.apps.youtube.app.watchwhile.MainActivity"
|
||||
|
||||
const val YOUTUBE_PACKAGE_NAME = "com.google.android.youtube"
|
||||
const val REVANCED_YOUTUBE_PACKAGE_NAME = "app.revanced.android.youtube"
|
||||
}
|
||||
@@ -164,7 +164,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
|
||||
addInstruction(
|
||||
index + 1,
|
||||
"invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->setToolbar(Landroid/widget/FrameLayout;)V"
|
||||
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setToolbar(Landroid/widget/FrameLayout;)V"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package app.revanced.patches.youtube.misc.spoof
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
@@ -16,9 +15,20 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;"
|
||||
|
||||
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
extensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;",
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
fixMediaFetchHotConfig = {
|
||||
is_19_34_or_greater
|
||||
},
|
||||
fixMediaFetchHotConfigAlternative = {
|
||||
// In 20.14 the flag was merged with 20.03 start playback flag.
|
||||
is_20_10_or_greater && !is_20_14_or_greater
|
||||
},
|
||||
fixParsePlaybackResponseFeatureFlag = {
|
||||
is_20_03_or_greater
|
||||
},
|
||||
|
||||
block = {
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
@@ -35,16 +45,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
versionCheckPatch
|
||||
)
|
||||
},
|
||||
fixMediaFetchHotConfigChanges = {
|
||||
is_19_34_or_greater
|
||||
},
|
||||
fixMediaFetchHotConfigAlternativeChanges = {
|
||||
// In 20.14 the flag was merged with 20.03 start playback flag.
|
||||
is_20_10_or_greater && !is_20_14_or_greater
|
||||
},
|
||||
fixParsePlaybackResponseFeatureFlag = {
|
||||
is_20_03_or_greater
|
||||
},
|
||||
|
||||
executeBlock = {
|
||||
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
|
||||
|
||||
@@ -61,6 +62,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
summaryKey = null,
|
||||
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
|
||||
),
|
||||
SwitchPreference("revanced_spoof_video_streams_av1"),
|
||||
ListPreference(
|
||||
key = "revanced_spoof_video_streams_language",
|
||||
// Language strings are declared in Setting patch.
|
||||
@@ -72,10 +74,5 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,159 +1,36 @@
|
||||
package app.revanced.patches.youtube.video.audio
|
||||
|
||||
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.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.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
|
||||
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/youtube/patches/ForceOriginalAudioPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val forceOriginalAudioPatch = bytecodePatch(
|
||||
name = "Force original audio",
|
||||
description = "Adds an option to always use the original audio track.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
versionCheckPatch
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
"20.07.39",
|
||||
"20.13.41",
|
||||
"20.14.43",
|
||||
val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
block = {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
settingsPatch,
|
||||
versionCheckPatch
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
addResources("youtube", "video.audio.forceOriginalAudioPatch")
|
||||
|
||||
PreferenceScreen.VIDEO.addPreferences(
|
||||
SwitchPreference(
|
||||
key = "revanced_force_original_audio",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.ForceOriginalAudioSwitchPreference"
|
||||
compatibleWith(
|
||||
"com.google.android.youtube"(
|
||||
"19.34.42",
|
||||
"20.07.39",
|
||||
"20.13.41",
|
||||
"20.14.43",
|
||||
)
|
||||
)
|
||||
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setPreferredLanguage()V"
|
||||
)
|
||||
|
||||
// Disable feature flag that ignores the default track flag
|
||||
// and instead overrides to the user region language.
|
||||
if (is_20_07_or_greater) {
|
||||
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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
fixUseLocalizedAudioTrackFlag = is_20_07_or_greater,
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
|
||||
preferenceScreen = PreferenceScreen.VIDEO,
|
||||
)
|
||||
|
||||
@@ -14,6 +14,13 @@ import java.nio.file.StandardCopyOption
|
||||
|
||||
private val classLoader = object {}.javaClass.classLoader
|
||||
|
||||
/**
|
||||
* Removes a node from its parent.
|
||||
*
|
||||
* @return The node that was removed (object this method was called on).
|
||||
*/
|
||||
fun Node.removeFromParent() : Node = parentNode.removeChild(this)
|
||||
|
||||
/**
|
||||
* Returns a sequence for all child nodes.
|
||||
*/
|
||||
@@ -70,8 +77,13 @@ fun ResourcePatchContext.copyResources(
|
||||
for (resourceGroup in resources) {
|
||||
resourceGroup.resources.forEach { resource ->
|
||||
val resourceFile = "${resourceGroup.resourceDirectoryName}/$resource"
|
||||
val stream = inputStreamFromBundledResource(sourceResourceDirectory, resourceFile)
|
||||
if (stream == null) {
|
||||
throw IllegalArgumentException("Could not find resource: $resourceFile " +
|
||||
"in directory: $sourceResourceDirectory")
|
||||
}
|
||||
Files.copy(
|
||||
inputStreamFromBundledResource(sourceResourceDirectory, resourceFile)!!,
|
||||
stream,
|
||||
targetResourceDirectory.resolve(resourceFile).toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING,
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,11 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
</patch>
|
||||
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch">
|
||||
@@ -34,6 +40,9 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
<patch id="misc.privacy.sanitizeSharingLinksPatch">
|
||||
@@ -200,8 +209,10 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.themePatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
</patch>
|
||||
@@ -227,9 +238,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.links.openLinksExternallyPatch">
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
</patch>
|
||||
@@ -253,6 +261,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,11 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
</patch>
|
||||
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch">
|
||||
@@ -34,6 +40,9 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
<patch id="misc.privacy.sanitizeSharingLinksPatch">
|
||||
@@ -200,8 +209,10 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.themePatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
</patch>
|
||||
@@ -227,9 +238,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.links.openLinksExternallyPatch">
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
</patch>
|
||||
@@ -253,6 +261,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,11 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
</patch>
|
||||
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch">
|
||||
@@ -35,6 +41,9 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
<patch id="misc.privacy.sanitizeSharingLinksPatch">
|
||||
@@ -201,8 +210,10 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.themePatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
</patch>
|
||||
@@ -229,9 +240,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.links.openLinksExternallyPatch">
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
</patch>
|
||||
@@ -255,6 +263,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Tətbiq adı</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Fərdi</string>
|
||||
<string name="revanced_custom_branding_icon_title">Tətbiq simvolu</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Orijinal</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced ən kiçik</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced ölçüləndirilmiş</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Fərdi</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Yoxlamalar uğursuz oldu</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Xidməti veb saytı aç</string>
|
||||
@@ -120,6 +133,13 @@ Oynatma işləməyə bilər"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Bu tənzimləməni qapatmaq oynatma problemlərinə səbəb ola bilər.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">İlkin qəbuledici</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Orijinal səs dilini zorla</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Orijinal səs dilini istifadə</string>
|
||||
<string name="revanced_force_original_audio_summary_off">İlkin səs istifadəsi</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Bu funksiyanı istifadə etmək üçün \"Video yayımları saxtalaşdırı\" Android Studio savayı istənilən qəbulediciyə dəyiş</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Sazlama</string>
|
||||
<string name="revanced_debug_screen_summary">Sazlama seçimlərini aktiv/qeyri-aktiv et</string>
|
||||
@@ -361,7 +381,7 @@ Hər halda, bunu aktivləşdirmə IP ünvanınız kimi bəzi istifadəçi məlum
|
||||
<string name="revanced_hide_comments_ai_chat_summary_title">Sİ söhbət xülasəsini gizlət</string>
|
||||
<string name="revanced_hide_comments_ai_chat_summary_summary_on">Sİ söhbət xülasəsi gizlidir</string>
|
||||
<string name="revanced_hide_comments_ai_chat_summary_summary_off">Sİ söhbət xülasəsi görünür</string>
|
||||
<string name="revanced_hide_comments_ai_summary_title">AI Ṣərhlər Xülasəsini Gizlət</string>
|
||||
<string name="revanced_hide_comments_ai_summary_title">AI şərhlər xülasəsini gizlət</string>
|
||||
<string name="revanced_hide_comments_ai_summary_summary_on">Sİ şərhlər xülasəsi gizlidir</string>
|
||||
<string name="revanced_hide_comments_ai_summary_summary_off">Sİ şərhlər xülasəsi görünür</string>
|
||||
<string name="revanced_hide_comments_channel_guidelines_title">Kanal təlimatlarını gizlət</string>
|
||||
@@ -398,19 +418,19 @@ Hər halda, bunu aktivləşdirmə IP ünvanınız kimi bəzi istifadəçi məlum
|
||||
<string name="revanced_custom_filter_strings_summary">Yeni sətirlə ayrılmış filtr üçün element yol qurucusu sətirlərinin siyahısı</string>
|
||||
<string name="revanced_custom_filter_toast_invalid_syntax">Etibarsız fərdi filtr: %s</string>
|
||||
<string name="revanced_hide_view_count_title">Baxış sayını gizlət</string>
|
||||
<string name="revanced_hide_view_count_summary_on">Baxış sayı lentdə və axtarış nəticələrində gizlədilib</string>
|
||||
<string name="revanced_hide_view_count_summary_off">Baxış sayı lentdə və axtarış nəticələrində göstərilib</string>
|
||||
<string name="revanced_hide_view_count_summary_on">Baxış sayı axın və axtarış nəticələrində gizlidir</string>
|
||||
<string name="revanced_hide_view_count_summary_off">Baxış sayı axın və axtarış nəticələrində görünür</string>
|
||||
<!-- Translations should lanaguge similar to revanced_hide_upload_time_user_dialog_message -->
|
||||
<string name="revanced_hide_view_count_user_dialog_message">"Məhdudiyyətlər:
|
||||
• Shorts rəfləri, kanal səhifələri və axtarış nəticələri hələ də baxış saylarını göstərə bilər
|
||||
• Bu funksiya avtomobil form faktoru ilə işləmir"</string>
|
||||
<string name="revanced_hide_upload_time_title">Yükləmə vaxtını gizlət</string>
|
||||
<string name="revanced_hide_upload_time_summary_on">Yükləmə vaxtı lentdə və axtarış nəticələrində gizlədilib</string>
|
||||
<string name="revanced_hide_upload_time_summary_off">Yükləmə vaxtı lentdə və axtarış nəticələrində göstərilir</string>
|
||||
• Shorts bölmələri, kanal səhifələri və axtarış nəticələri yenə də baxış sayını göstərə bilər
|
||||
• Bu xüsusiyyət avtomobil forma göstərici ilə işləmir"</string>
|
||||
<string name="revanced_hide_upload_time_title">Yüklənilmə vaxtını gizlət</string>
|
||||
<string name="revanced_hide_upload_time_summary_on">Yüklənilmə vaxtı axın və axtarış nəticələrində gizlidir</string>
|
||||
<string name="revanced_hide_upload_time_summary_off">Yüklənilmə vaxtı axın və axtarış nəticələrində göstərilir</string>
|
||||
<!-- Translations should lanaguge similar to revanced_hide_view_count_user_dialog_message -->
|
||||
<string name="revanced_hide_upload_time_user_dialog_message">"Məhdudiyyətlər:
|
||||
• Shorts rəflərində, kanal səhifələrində və axtarış nəticələrində yükləmə vaxtları hələ də göstərilə bilər
|
||||
• Bu funksiya avtomobil form faktoru ilə işləmir"</string>
|
||||
• Shorts bölmələri, kanal səhifələri və axtarış nəticələri yüklənilən vaxtı yenə də göstərə bilər
|
||||
• Bu xüsusiyyət avtomobil forma göstərici ilə işləmir"</string>
|
||||
<string name="revanced_hide_keyword_content_screen_title">Açar söz məzmununu gizlət</string>
|
||||
<string name="revanced_hide_keyword_content_screen_summary">Açar söz filtrləri ilə axtarış və axın videolarını gizlət</string>
|
||||
<string name="revanced_hide_keyword_content_home_title">Ev videolarını açar sözlərə görə gizlət</string>
|
||||
@@ -862,7 +882,7 @@ Səs treki menyusunu göstərmək üçün \"Video yayımları saxtalaşdır\"ı
|
||||
<string name="revanced_hide_shorts_location_label_title">Məkan etiketini gizlət</string>
|
||||
<string name="revanced_hide_shorts_location_label_summary_on">Məkan etiketi gizlidir</string>
|
||||
<string name="revanced_hide_shorts_location_label_summary_off">Məkan etiketi göstərilir</string>
|
||||
<string name="revanced_hide_shorts_new_posts_button_title">Yeni elanları gizlət düyməsi</string>
|
||||
<string name="revanced_hide_shorts_new_posts_button_title">Yeni elanlar düyməsini gizlət</string>
|
||||
<string name="revanced_hide_shorts_new_posts_button_summary_on">Yeni elanlar düyməsi gizlidir</string>
|
||||
<string name="revanced_hide_shorts_new_posts_button_summary_off">Yeni elanlar düyməsi göstərilir</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_title">Dayandırma örtük düymələrini gizlət</string>
|
||||
@@ -1402,11 +1422,13 @@ Kiçik oynadıcı ekrandan sola və ya sağa sürüklənə bilər"</string>
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">İrəliləyiş cizgisi vurğu rəngi</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Etibarsız irəliləmə cizgisi rəng dəyəri</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Başlıq simvolu</string>
|
||||
<string name="revanced_header_logo_entry_1">İlkin</string>
|
||||
<string name="revanced_header_logo_entry_2">Müntəzəm</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">Ən kiçik ReVanced</string>
|
||||
<string name="revanced_header_logo_entry_6">Fərdi</string>
|
||||
</patch>
|
||||
@@ -1512,13 +1534,6 @@ Bunu aktivləşdirmə daha yüksək video keyfiyyətləri əngəlin silə bilər
|
||||
<string name="revanced_external_browser_summary_on">Xarici brauzerdə bağlantıların açılması</string>
|
||||
<string name="revanced_external_browser_summary_off">Tətbiqdaxili brauzerdə bağlantıların açılması</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Orijinal səs dilini zorla</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Orijinal səs dilini istifadə</string>
|
||||
<string name="revanced_force_original_audio_summary_off">İlkin səs istifadəsi</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Bu funksiyanı istifadə etmək üçün \"Video yayımları saxtalaşdırı\" Android Studio savayı istənilən qəbulediciyə dəyiş</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Avtomatik</string>
|
||||
@@ -1603,6 +1618,14 @@ Məhdudiyyətlər:
|
||||
<string name="revanced_slide_to_seek_summary_off">Axtarmaq üçün sürüşdürmə aktiv deyil</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Android VR AV1-ə icazə ver</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Video kodlayıcı AVC (H.264), VP9 və ya AV1-dir
|
||||
|
||||
Oynatma ilişə bilər və ya kadrlar buraxıla bilər"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Video kodlayıcı AVC (H.264) və ya VP9-dur</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Bu tənzimləməni aktivləşdirmə proqram təminatlı AV1 kodlayıcı istifadə edə bilər.
|
||||
|
||||
Video oynatma AV1 ilə ilişə bilər və ya kadrlar buraxıla bilər."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Saxtakarlıq yan təsirləri</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Təcrübi qəbuledici və hər vaxt işləməyi dayandıra bilər</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Video 01:00-da dayana bilər və ya bəzi bölgələrdə mövcud olmaya bilər</string>
|
||||
@@ -1622,6 +1645,8 @@ Məhdudiyyətlər:
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Haqqında</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Reklamlar</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Назва праграмы</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Карыстальніцкая</string>
|
||||
<string name="revanced_custom_branding_icon_title">Значок праграмы</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Арыгінал</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced мінімальны</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced маштабаваны</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Карыстальніцкі</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Праверкі не пройдзены</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Адкрыць афіцыйны вэб-сайт</string>
|
||||
@@ -120,6 +133,13 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Адключэнне гэтай налады можа выклікаць праблемы з прайграваннем.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Клиент по умолчанию</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Вымушаная арыгінальная мова аўдыё</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Выкарыстоўваць арыгінальную мову аўдыя</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Выкарыстанне аўдыё па змаўчанні</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Каб выкарыстаць гэтую функцыю, змяніце \'Падмена відэаструменяў\' на любога кліента, акрамя Android Studio</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Адладка</string>
|
||||
<string name="revanced_debug_screen_summary">Уключыць або выключыць параметры адладкі</string>
|
||||
@@ -1404,11 +1424,13 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Акцэнтны колер пошуку</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Неверное значение цвета ползунка прогресса</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Лагатып загалоўка</string>
|
||||
<string name="revanced_header_logo_entry_1">Па змаўчанні</string>
|
||||
<string name="revanced_header_logo_entry_2">Звычайны</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced мінімальны</string>
|
||||
<string name="revanced_header_logo_entry_6">Карыстальніцкі</string>
|
||||
</patch>
|
||||
@@ -1514,13 +1536,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_external_browser_summary_on">Адкрыццё спасылак у знешнім браўзеры</string>
|
||||
<string name="revanced_external_browser_summary_off">Адкрыццё спасылак ва ўбудаваным браўзеры</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Вымушаная арыгінальная мова аўдыё</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Выкарыстоўваць арыгінальную мову аўдыя</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Выкарыстанне аўдыё па змаўчанні</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Каб выкарыстаць гэтую функцыю, змяніце \'Падмена відэаструменяў\' на любога кліента, акрамя Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Аўто</string>
|
||||
@@ -1605,6 +1620,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">Слайд для пошуку не ўключаны</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Дазволіць Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Відэакодэк — AVC (H.264), VP9 або AV1
|
||||
|
||||
Праграмаванне можа заікацца або прапускаць кадры"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Відэакодэк — AVC (H.264) або VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Уключэнне гэтай налады можа выкарыстоўваць праграмнае дэкадаванне AV1.
|
||||
|
||||
Прайграванне відэа з AV1 можа заікацца або прапускаць кадры."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Пабочныя эфекты падробкі</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Эксперыментальны кліент і можа спыніць працу ў любы час</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Відэа можа спыніцца на 1:00, ці можа быць недаступным у некаторых рэгіёнах</string>
|
||||
@@ -1624,6 +1647,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Пра</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Рэклама</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Име на приложението</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Персонализиран</string>
|
||||
<string name="revanced_custom_branding_icon_title">Икона на приложението</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Оригинален</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced минимален</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced мащабиран</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Персонализиран</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Проверката е неуспешна</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Отворете официалния уебсайт</string>
|
||||
@@ -120,6 +133,13 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Изключването на тази настройка може да причини проблеми с възпроизвеждането.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Клиент по подразбиране</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Принудително оригинално аудио език</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Използване на оригиналния език на аудиото</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Използване на аудио по подразбиране</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">За да използвате тази функция, променете \'Фалшифициране на видео потоци\' на всеки клиент, освен Android Studio</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Отстраняване на грешки</string>
|
||||
<string name="revanced_debug_screen_summary">Активиране или деактивиране на отстраняването на грешки</string>
|
||||
@@ -1403,11 +1423,13 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Цветът на лентата за търсене</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Невалидна стойност за цвят на лентата на прогреса</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Лого в заглавката</string>
|
||||
<string name="revanced_header_logo_entry_1">По подразбиране</string>
|
||||
<string name="revanced_header_logo_entry_2">Обикновено</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced минимално</string>
|
||||
<string name="revanced_header_logo_entry_6">По избор</string>
|
||||
</patch>
|
||||
@@ -1513,13 +1535,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_external_browser_summary_on">Отваряне на връзки във външен браузър</string>
|
||||
<string name="revanced_external_browser_summary_off">Отваряне на връзки във вграден браузър</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Принудително оригинално аудио език</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Използване на оригиналния език на аудиото</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Използване на аудио по подразбиране</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">За да използвате тази функция, променете \'Фалшифициране на видео потоци\' на всеки клиент, освен Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Авто</string>
|
||||
@@ -1604,6 +1619,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">Слайд за превъртане е деактивиран</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Разрешаване на Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Видеокодекът е AVC (H.264), VP9 или AV1
|
||||
|
||||
Възпроизвеждането може да заеква или да пропуска кадри"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Видеокодекът е AVC (H.264) или VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Разрешаването на тази настройка може да използва софтуерно AV1 декодиране.
|
||||
|
||||
Възпроизвеждането на видео с AV1 може да заеква или да пропуска кадри."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Странични ефекти от подменянето</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Експериментален клиент и може да спре да работи по всяко време</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Видеото може да спре на 1:00 или може да не е налично в някои региони</string>
|
||||
@@ -1623,6 +1646,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Относно</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Реклами</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">অ্যাপের নাম</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">কাস্টম</string>
|
||||
<string name="revanced_custom_branding_icon_title">অ্যাপ আইকন</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">মূল</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">রিভ্যান্সড মিনিমাল</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">রিভ্যান্সড স্কেলড</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">কাস্টম</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">চেক ফেইল করেছে</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">অফিশ্যাল ওয়েবসাইট খুলুন</string>
|
||||
@@ -120,6 +133,13 @@ MicroG-এর জন্য ব্যাটারি অপ্টিমাইজ
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">এই সেটিং বন্ধ করলে প্লেব্যাক সমস্যা হতে পারে।</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">ডিফল্ট ক্লায়েন্ট</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">মূল অডিও ভাষা বলপূর্বক চালু করুন</string>
|
||||
<string name="revanced_force_original_audio_summary_on">মূল অডিও ভাষা ব্যবহার করা হচ্ছে</string>
|
||||
<string name="revanced_force_original_audio_summary_off">ডিফল্ট অডিও ব্যবহার করছে</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">এই বৈশিষ্ট্যটি ব্যবহার করতে, \'ভিডিও স্ট্রিম স্পুফ করুন\' অ্যান্ড্রয়েড স্টুডিও ছাড়া অন্য কোনো ক্লায়েন্টে পরিবর্তন করুন</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">ডিবাগিং</string>
|
||||
<string name="revanced_debug_screen_summary">ডিবাগিং অপশন সক্রিয় বা নিষ্ক্রিয় করুন</string>
|
||||
@@ -1399,11 +1419,13 @@ Miniplayer স্ক্রিন থেকে বামে বা ডানে
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">সিকবারের এক্সেন্ট রঙ</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">অবৈধ সিকবার রঙ মান</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">হেডার লোগো</string>
|
||||
<string name="revanced_header_logo_entry_1">ডিফল্ট</string>
|
||||
<string name="revanced_header_logo_entry_2">সাধারণ</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">রিভ্যান্সড মিনিমাল</string>
|
||||
<string name="revanced_header_logo_entry_6">কাস্টম</string>
|
||||
</patch>
|
||||
@@ -1509,13 +1531,6 @@ DeArrow সম্পর্কে আরও জানতে এখানে ট
|
||||
<string name="revanced_external_browser_summary_on">বাহ্যিক ব্রাউজারে লিঙ্ক খোলা হচ্ছে</string>
|
||||
<string name="revanced_external_browser_summary_off">ইন-অ্যাপ ব্রাউজারে লিঙ্ক খোলা হচ্ছে</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">মূল অডিও ভাষা বলপূর্বক চালু করুন</string>
|
||||
<string name="revanced_force_original_audio_summary_on">মূল অডিও ভাষা ব্যবহার করা হচ্ছে</string>
|
||||
<string name="revanced_force_original_audio_summary_off">ডিফল্ট অডিও ব্যবহার করছে</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">এই বৈশিষ্ট্যটি ব্যবহার করতে, \'ভিডিও স্ট্রিম স্পুফ করুন\' অ্যান্ড্রয়েড স্টুডিও ছাড়া অন্য কোনো ক্লায়েন্টে পরিবর্তন করুন</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">স্বতস্ফূর্তভাবে</string>
|
||||
@@ -1600,6 +1615,14 @@ DeArrow সম্পর্কে আরও জানতে এখানে ট
|
||||
<string name="revanced_slide_to_seek_summary_off">ভিডিওর নির্দিষ্ট অংশে যেতে টানুন সক্রিয় করা হয়নি</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">অ্যান্ড্রয়েড VR AV1 অনুমতি দিন</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"ভিডিও কোডেক হল AVC (H.264), VP9, অথবা AV1
|
||||
|
||||
প্লেব্যাক আটকে যেতে পারে বা ফ্রেম বাদ দিতে পারে"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">ভিডিও কোডেক হল AVC (H.264) অথবা VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"এই সেটিংটি চালু করলে সফটওয়্যার AV1 ডিকোডিং ব্যবহার হতে পারে।
|
||||
|
||||
AV1 সহ ভিডিও প্লেব্যাক আটকে যেতে পারে বা ফ্রেম বাদ দিতে পারে।"</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">স্পুফিংয়ের পার্শ্বপ্রতিক্রিয়া</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• পরীক্ষামূলক ক্লায়েন্ট এবং যেকোনো সময় কাজ করা বন্ধ করতে পারে</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• ভিডিও ১:০০ মিনিটে বন্ধ হতে পারে, অথবা কিছু অঞ্চলে উপলব্ধ নাও হতে পারে</string>
|
||||
@@ -1619,6 +1642,8 @@ DeArrow সম্পর্কে আরও জানতে এখানে ট
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">সম্পর্কে</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">বিজ্ঞাপন</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,11 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
</patch>
|
||||
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch">
|
||||
@@ -34,6 +40,9 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
<patch id="misc.privacy.sanitizeSharingLinksPatch">
|
||||
@@ -200,8 +209,10 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.themePatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
</patch>
|
||||
@@ -227,9 +238,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.links.openLinksExternallyPatch">
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
</patch>
|
||||
@@ -253,6 +261,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,11 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
</patch>
|
||||
<patch id="misc.dns.checkWatchHistoryDomainNameResolutionPatch">
|
||||
@@ -34,6 +40,9 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
</patch>
|
||||
<patch id="misc.privacy.sanitizeSharingLinksPatch">
|
||||
@@ -200,8 +209,10 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.themePatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
|
||||
</patch>
|
||||
@@ -227,9 +238,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.links.openLinksExternallyPatch">
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
</patch>
|
||||
@@ -253,6 +261,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
</patch>
|
||||
<patch id="ad.video.hideVideoAdsPatch">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Název aplikace</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Vlastní</string>
|
||||
<string name="revanced_custom_branding_icon_title">Ikona aplikace</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Původní</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimální</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced škálované</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Vlastní</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Kontrola proběhla neúspěšně</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Otevřít oficiální webovou stránku</string>
|
||||
@@ -120,6 +133,13 @@ Přehrávání nemusí fungovat"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Vypnutí tohoto nastavení může způsobit problémy s přehráváním.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Výchozí klient</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Vynutit původní jazyk zvuku</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Použít původní jazyk zvuku</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Používání výchozího zvuku</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Chcete-li použít tuto funkci, změňte \'Zfalšovat video streamy\' na libovolného klienta kromě Android Studia</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Debugování</string>
|
||||
<string name="revanced_debug_screen_summary">Povolit nebo zakázat debugovací možnosti</string>
|
||||
@@ -1403,11 +1423,13 @@ Omezení: Použití tlačítka zpět na panelu nástrojů nemusí fungovat"</str
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Zvýrazněná barva posuvníku</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Neplatná hodnota barvy posuvníku</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Logo záhlaví</string>
|
||||
<string name="revanced_header_logo_entry_1">Výchozí</string>
|
||||
<string name="revanced_header_logo_entry_2">Běžné</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced minimální</string>
|
||||
<string name="revanced_header_logo_entry_6">Vlastní</string>
|
||||
</patch>
|
||||
@@ -1513,13 +1535,6 @@ Povolením této funkce lze odemknout vyšší kvality videa"</string>
|
||||
<string name="revanced_external_browser_summary_on">Otevírání odkazů v externím prohlížeči</string>
|
||||
<string name="revanced_external_browser_summary_off">Otevírání odkazů v prohlížeči v aplikaci</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Vynutit původní jazyk zvuku</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Použít původní jazyk zvuku</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Používání výchozího zvuku</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Chcete-li použít tuto funkci, změňte \'Zfalšovat video streamy\' na libovolného klienta kromě Android Studia</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Automaticky</string>
|
||||
@@ -1604,6 +1619,14 @@ Omezení:
|
||||
<string name="revanced_slide_to_seek_summary_off">Posun pro hledání není povolen</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Povolit Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Video kodek je AVC (H.264), VP9 nebo AV1
|
||||
|
||||
Přehrávání se může zasekávat nebo přeskakovat snímky"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Video kodek je AVC (H.264) nebo VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Povolení tohoto nastavení může využívat softwarové dekódování AV1.
|
||||
|
||||
Přehrávání videa s AV1 se může sekat nebo vypadávat snímky."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Vedlejší účinky maskování</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Experimentální klient a může kdykoli přestat fungovat</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Video se může zastavit v 1:00 nebo nemusí být dostupné v některých oblastech</string>
|
||||
@@ -1623,6 +1646,8 @@ Omezení:
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">O aplikaci</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Reklamy</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Appnavn</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Tilpasset</string>
|
||||
<string name="revanced_custom_branding_icon_title">Appikon</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Original</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimal</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced skaleret</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Tilpasset</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Kontrol mislykkedes</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Åbn officiel hjemmeside</string>
|
||||
@@ -120,6 +133,13 @@ Afspilning fungerer muligvis ikke"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Deaktivering af denne indstilling kan forårsage afspilningsproblemer.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Standard klient</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Tving originalt lydsprog</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Bruger originalt lydsprog</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Brug standard lyd</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">For at bruge denne funktion skal du ændre \"Forfalsk videostreams\" til en hvilken som helst klient undtagen Android Studio</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Fejlfinding</string>
|
||||
<string name="revanced_debug_screen_summary">Aktivér eller deaktiver fejlfindingsindstillinger</string>
|
||||
@@ -1405,11 +1425,13 @@ Miniafspiller kan trækkes ud over skærmen til venstre eller højre"</string>
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Søgelinjens accentfarve</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Ugyldig søgelinje farveværdi</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Sidehovedlogo</string>
|
||||
<string name="revanced_header_logo_entry_1">Standard</string>
|
||||
<string name="revanced_header_logo_entry_2">Normal</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced minimal</string>
|
||||
<string name="revanced_header_logo_entry_6">Brugerdefineret</string>
|
||||
</patch>
|
||||
@@ -1515,13 +1537,6 @@ Aktivering af dette kan låse op for højere videokvalitet"</string>
|
||||
<string name="revanced_external_browser_summary_on">Åbner links i ekstern browser</string>
|
||||
<string name="revanced_external_browser_summary_off">Åbner links i browser i appen</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Tving originalt lydsprog</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Bruger originalt lydsprog</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Brug standard lyd</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">For at bruge denne funktion skal du ændre \"Forfalsk videostreams\" til en hvilken som helst klient undtagen Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Automatisk</string>
|
||||
@@ -1606,6 +1621,14 @@ Begrænsninger:
|
||||
<string name="revanced_slide_to_seek_summary_off">Dias til søgning er ikke aktiveret</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Tillad Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Videocodec er AVC (H.264), VP9 eller AV1
|
||||
|
||||
Afspilning kan hakke eller miste billeder"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Videocodec er AVC (H.264) eller VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Aktivering af denne indstilling kan bruge software AV1-afkodning.
|
||||
|
||||
Videoafspilning med AV1 kan hakke eller tabe billeder."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Bivirkninger ved spoofing</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Eksperimentel klient og kan stoppe med at fungere når som helst</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Videoen kan stoppe ved 1:00, eller er muligvis ikke tilgængelig i visse regioner</string>
|
||||
@@ -1625,6 +1648,8 @@ Begrænsninger:
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Om</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Annoncer</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">App-Name</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Benutzerdefiniert</string>
|
||||
<string name="revanced_custom_branding_icon_title">App-Symbol</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Original</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimal</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced skaliert</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Benutzerdefiniert</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Prüfungen fehlgeschlagen</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Offizielle Website öffnen</string>
|
||||
@@ -120,6 +133,13 @@ Die Wiedergabe funktioniert möglicherweise nicht"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Das Deaktivieren dieser Einstellung kann Wiedergabeprobleme verursachen.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Standard-Client</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Original Audio erzwingen</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Original-Audiosprache verwenden</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Standardaudio verwenden</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Um diese Funktion zu nutzen, ändere \"Video-Streams fälschen\" auf einen beliebigen Client außer Android Studio</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Fehlerbehebung</string>
|
||||
<string name="revanced_debug_screen_summary">Aktiviert oder deaktiviert Debugging-Optionen</string>
|
||||
@@ -1400,11 +1420,13 @@ Der Mini-Player kann mit einer Wischgeste vom Bildschirm nach links oder rechts
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Die Akzentfarbe der Fortschrittsanzeige</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Ungültiger Suchleisten-Farbwert</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Header-Logo</string>
|
||||
<string name="revanced_header_logo_entry_1">Standard</string>
|
||||
<string name="revanced_header_logo_entry_2">Regulär</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced Minimal</string>
|
||||
<string name="revanced_header_logo_entry_6">Benutzerdefiniert</string>
|
||||
</patch>
|
||||
@@ -1510,13 +1532,6 @@ Durch Aktivieren dieser Option können höhere Videoqualitäten freigeschaltet w
|
||||
<string name="revanced_external_browser_summary_on">Links im externen Browser öffnen</string>
|
||||
<string name="revanced_external_browser_summary_off">Links im In-App-Browser öffnen</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Original Audio erzwingen</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Original-Audiosprache verwenden</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Standardaudio verwenden</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Um diese Funktion zu nutzen, ändere \"Video-Streams fälschen\" auf einen beliebigen Client außer Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Autom</string>
|
||||
@@ -1601,6 +1616,14 @@ Einschränkungen:
|
||||
<string name="revanced_slide_to_seek_summary_off">Slide zum Suchen ist nicht aktiviert</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Android VR AV1 zulassen</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Video-Codec ist AVC (H.264), VP9 oder AV1
|
||||
|
||||
Die Wiedergabe kann stottern oder Frames verlieren"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Video-Codec ist AVC (H.264) oder VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Durch Aktivierung dieser Einstellung kann Software-AV1-Decodierung verwendet werden.
|
||||
|
||||
Die Videowiedergabe mit AV1 kann stottern oder Bilder überspringen."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Nebenwirkungen des Spoofings</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Experimenteller Client und kann jederzeit aufhören zu funktionieren</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Video kann um 1:00 Uhr stoppen oder ist möglicherweise in einigen Regionen nicht verfügbar</string>
|
||||
@@ -1620,6 +1643,8 @@ Einschränkungen:
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Über</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Werbung</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Όνομα εφαρμογής</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Προσαρμοσμένο</string>
|
||||
<string name="revanced_custom_branding_icon_title">Εικονίδιο εφαρμογής</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Αρχικό</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced απλό</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced κλιμακωμένο</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Προσαρμοσμένο</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Αποτυχία ελέγχων</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Άνοιγμα επίσημης ιστοσελίδας</string>
|
||||
@@ -120,6 +133,13 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Η απενεργοποίηση αυτής της ρύθμισης ενδέχεται να προκαλέσει προβλήματα αναπαραγωγής.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Προεπιλεγμένο πρόγραμμα πελάτη</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Εξαναγκασμός αρχικής γλώσσας ήχου</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Χρησιμοποιείται η αρχική γλώσσα ήχου</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Χρησιμοποιείται ο προεπιλεγμένος ήχος</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Για να χρησιμοποιήσετε αυτήν τη λειτουργία, αλλάξτε την επιλογή «Παραποίηση ροών βίντεο» σε οποιονδήποτε πελάτη εκτός από το Android Studio</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Εντοπισμός σφαλμάτων</string>
|
||||
<string name="revanced_debug_screen_summary">Ενεργοποίηση ή απενεργοποίηση επιλογών εντοπισμού σφαλμάτων</string>
|
||||
@@ -952,8 +972,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.relatedvideooverlay.hideRelatedVideoOverlayPatch">
|
||||
<string name="revanced_hide_related_videos_overlay_title">Σχετικά βίντεο στην πλήρη οθόνη</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">Κρυμμένα\n\nΑφορά τα σχετικά βίντεο της τελικής οθόνης στη λειτουργία πλήρους οθόνης</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">Εμφανίζονται\n\nΑφορά τα σχετικά βίντεο της τελικής οθόνης στη λειτουργία πλήρους οθόνης</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_on">Κρυμμένα</string>
|
||||
<string name="revanced_hide_related_videos_overlay_summary_off">Εμφανίζονται</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.time.hideTimestampPatch">
|
||||
<string name="revanced_hide_timestamp_title">Χρονική πρόοδος βίντεο</string>
|
||||
@@ -1404,11 +1424,13 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Το χρώμα έμφασης της γραμμής προόδου</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Μη έγκυρη τιμή χρώματος γραμμής προόδου</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Λογότυπο επικεφαλίδας</string>
|
||||
<string name="revanced_header_logo_entry_1">Προεπιλογή</string>
|
||||
<string name="revanced_header_logo_entry_2">Κανονικό</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced απλό</string>
|
||||
<string name="revanced_header_logo_entry_6">Προσαρμοσμένο</string>
|
||||
</patch>
|
||||
@@ -1512,13 +1534,6 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_external_browser_summary_on">Οι σύνδεσμοι ανοίγουν σε εξωτερικό πρόγραμμα περιήγησης</string>
|
||||
<string name="revanced_external_browser_summary_off">Οι σύνδεσμοι ανοίγουν στο εσωτερικό πρόγραμμα περιήγησης της εφαρμογής</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Εξαναγκασμός αρχικής γλώσσας ήχου</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Χρησιμοποιείται η αρχική γλώσσα ήχου</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Χρησιμοποιείται ο προεπιλεγμένος ήχος</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Για να χρησιμοποιήσετε αυτήν τη λειτουργία, αλλάξτε την επιλογή «Παραποίηση ροών βίντεο» σε οποιονδήποτε πελάτη εκτός από το Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Αυτόματη</string>
|
||||
@@ -1603,6 +1618,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">Η χειρονομία συρσίματος για αναζήτηση στη γραμμή προόδου είναι απενεργοποιημένη</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Να επιτρέπεται ο κωδικοποιητής Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Ο κωδικοποιητής βίντεο είναι ο AVC (H.264), ο VP9 ή ο AV1
|
||||
|
||||
Η αναπαραγωγή μπορεί να κομπιάζει ή να χάνει καρέ"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Ο κωδικοποιητής βίντεο είναι ο AVC (H.264) ή ο VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Η ενεργοποίηση αυτής της ρύθμισης ενδέχεται να χρησιμοποιήσει αποκωδικοποίηση λογισμικού AV1.
|
||||
|
||||
Η αναπαραγωγή βίντεο μπορεί να κομπιάζει ή να χάνει καρέ."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Παρενέργειες παραποίησης</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Πειραματικός πελάτης και μπορεί να σταματήσει να λειτουργεί ανά πάσα στιγμή</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Το βίντεο μπορεί να σταματήσει στο 1:00 ή να μην είναι διαθέσιμο σε ορισμένες περιοχές</string>
|
||||
@@ -1622,6 +1645,8 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Σχετικά με</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Διαφημίσεις</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Nombre de la aplicación</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Personalizado</string>
|
||||
<string name="revanced_custom_branding_icon_title">Icono de la aplicación</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Original</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced mínimo</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced escalado</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Personalizado</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Comprobaciones fallidas</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Ir al sitio web oficial</string>
|
||||
@@ -120,6 +133,13 @@ La reproducción podría no funcionar"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Desactivar esta configuración puede causar problemas de reproducción.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Cliente por defecto</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Forzar idioma de audio original</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Usar el idioma de audio original</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Utilizando audio predeterminado</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Para usar esta función, cambia \'Falsificar transmisiones de vídeo\' a cualquier cliente excepto Android Studio</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Depuración</string>
|
||||
<string name="revanced_debug_screen_summary">Activar o desactivar las opciones de depuración</string>
|
||||
@@ -1394,11 +1414,13 @@ El minireproductor se puede arrastrar fuera de la pantalla hacia la izquierda o
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">El color de acento de la barra de búsqueda</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Valor de color de la barra de búsqueda inválido</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Logotipo del encabezado</string>
|
||||
<string name="revanced_header_logo_entry_1">Predeterminado</string>
|
||||
<string name="revanced_header_logo_entry_2">Normal</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced mínimo</string>
|
||||
<string name="revanced_header_logo_entry_6">Personalizado</string>
|
||||
</patch>
|
||||
@@ -1504,13 +1526,6 @@ Habilitar esto puede desbloquear calidades de vídeo más altas"</string>
|
||||
<string name="revanced_external_browser_summary_on">Abrir enlaces en el navegador externo</string>
|
||||
<string name="revanced_external_browser_summary_off">Abrir enlaces en el navegador integrado en la aplicación</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Forzar idioma de audio original</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Usar el idioma de audio original</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Utilizando audio predeterminado</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Para usar esta función, cambia \'Falsificar transmisiones de vídeo\' a cualquier cliente excepto Android Studio</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Automático</string>
|
||||
@@ -1595,6 +1610,12 @@ Limitaciones:
|
||||
<string name="revanced_slide_to_seek_summary_off">Slide to seek no está activado</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Permitir Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"El códec de video es AVC (H.264), VP9 o AV1
|
||||
|
||||
La reproducción puede tartamudear o perder fotogramas"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">El códec de video es AVC (H.264) o VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Habilitar esta configuración puede usar la decodificación de software AV1.\n\nLa reproducción de video con AV1 puede tartamudear o perder fotogramas."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Efectos secundarios de la falsificación</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• El cliente es experimental y puede dejar de funcionar en cualquier momento</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• El video puede detenerse en 1:00, o puede no estar disponible en algunas regiones</string>
|
||||
@@ -1614,6 +1635,8 @@ Limitaciones:
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Acerca de</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Anuncios</string>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding -->
|
||||
<!--
|
||||
|
||||
All strings must have a unique path, even if the same string is declared in two different apps.
|
||||
@@ -20,6 +21,18 @@ Second \"item\" text"</string>
|
||||
-->
|
||||
<resources>
|
||||
<app id="shared">
|
||||
<patch id="layout.branding.baseCustomBrandingPatch">
|
||||
<string name="revanced_custom_branding_name_title">Rakenduse nimi</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
|
||||
<string name="revanced_custom_branding_name_entry_5">Kohandatud</string>
|
||||
<string name="revanced_custom_branding_icon_title">Rakenduse ikoon</string>
|
||||
<string name="revanced_custom_branding_icon_entry_1">Algne</string>
|
||||
<!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimaalne</string>
|
||||
<string name="revanced_custom_branding_icon_entry_4">ReVanced skaleeritud</string>
|
||||
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Kohandatud</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Kontrollid ebaõnnestusid</string>
|
||||
<string name="revanced_check_environment_dialog_open_official_source_button">Ava oficial veebileht</string>
|
||||
@@ -120,6 +133,13 @@ Taasesitus ei pruugi töötada"</string>
|
||||
<string name="revanced_spoof_video_streams_user_dialog_message">Selle sätte väljalülitamine võib põhjustada taasesitusprobleeme.</string>
|
||||
<string name="revanced_spoof_video_streams_client_type_title">Vaikimisi klient</string>
|
||||
</patch>
|
||||
<patch id="misc.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Sunni originaalheli keel</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Algse helikeele kasutamine</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Kasutan vaikeheli</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Selle funktsiooni kasutamiseks muutke „Võltsitud videovood” mis tahes muule kliendile peale Android Studio.</string>
|
||||
</patch>
|
||||
<patch id="misc.debugging.enableDebuggingPatch">
|
||||
<string name="revanced_debug_screen_title">Veaotsing</string>
|
||||
<string name="revanced_debug_screen_summary">Veaotsinguvalikud lubamiseks või keelamiseks</string>
|
||||
@@ -1403,11 +1423,13 @@ Minimaalset mängijat saab lohistada ekraanilt vasakule või paremale"</string>
|
||||
<string name="revanced_seekbar_custom_color_accent_summary">Otsinguriba esiletõiduv värv</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Vigane edastusriba värvi väärtus</string>
|
||||
</patch>
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="layout.branding.changeHeaderPatch">
|
||||
<string name="revanced_header_logo_title">Päise logo</string>
|
||||
<string name="revanced_header_logo_entry_1">Vaikimisi</string>
|
||||
<string name="revanced_header_logo_entry_2">Tavaline</string>
|
||||
<!-- For this situation "Minimal" means minimalistic. It does not mean small or tiny. -->
|
||||
<!-- Translation of this should be identical to revanced_custom_branding_icon_entry_3 -->
|
||||
<string name="revanced_header_logo_entry_5">ReVanced minimaalne</string>
|
||||
<string name="revanced_header_logo_entry_6">Kohandatud</string>
|
||||
</patch>
|
||||
@@ -1513,13 +1535,6 @@ Selle lubamine võib avada kõrgema video kvaliteedi"</string>
|
||||
<string name="revanced_external_browser_summary_on">Linkide avamine välises brauseris</string>
|
||||
<string name="revanced_external_browser_summary_off">Linkide avamine rakendusesiseses brauseris</string>
|
||||
</patch>
|
||||
<patch id="video.audio.forceOriginalAudioPatch">
|
||||
<string name="revanced_force_original_audio_title">Sunni originaalheli keel</string>
|
||||
<string name="revanced_force_original_audio_summary_on">Algse helikeele kasutamine</string>
|
||||
<string name="revanced_force_original_audio_summary_off">Kasutan vaikeheli</string>
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<string name="revanced_force_original_audio_not_available">Selle funktsiooni kasutamiseks muutke „Võltsitud videovood” mis tahes muule kliendile peale Android Studio.</string>
|
||||
</patch>
|
||||
<patch id="video.quality.rememberVideoQualityPatch">
|
||||
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
|
||||
<string name="revanced_video_quality_default_entry_1">Automaatne</string>
|
||||
@@ -1604,6 +1619,14 @@ Piirangud:
|
||||
<string name="revanced_slide_to_seek_summary_off">Libistamine otsimiseks on keelatud</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<string name="revanced_spoof_video_streams_av1_title">Luba Android VR AV1</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_on">"Videokodek on AVC (H.264), VP9 või AV1
|
||||
|
||||
Taasesitus võib hakata kokutama või kaotada kaadreid"</string>
|
||||
<string name="revanced_spoof_video_streams_av1_summary_off">Videokodek on AVC (H.264) või VP9</string>
|
||||
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Selle seade lubamine võib kasutada tarkvara AV1 dekodeerimist.
|
||||
|
||||
AV1-ga videotaasesitus võib hakitud olla või kaadreid vahele jätta."</string>
|
||||
<string name="revanced_spoof_video_streams_about_title">Võltsimise kõrvalmõjud</string>
|
||||
<string name="revanced_spoof_video_streams_about_experimental">• Eksperimentaalne klient ja võib igal ajal töötamast lakata</string>
|
||||
<string name="revanced_spoof_video_streams_about_playback_failure">• Video võib peatuda kell 1:00 või ei pruugi olla teatud piirkondades saadaval</string>
|
||||
@@ -1623,6 +1646,8 @@ Piirangud:
|
||||
</patch>
|
||||
</app>
|
||||
<app id="music">
|
||||
<patch id="layout.branding.customBrandingPatch">
|
||||
</patch>
|
||||
<patch id="misc.settings.settingsPatch">
|
||||
<string name="revanced_settings_music_screen_0_about_title">Teave</string>
|
||||
<string name="revanced_settings_music_screen_1_ads_title">Reklaamid</string>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user