Compare commits

...

55 Commits

Author SHA1 Message Date
semantic-release-bot
1196b1a147 chore: Release v5.46.0-dev.1 [skip ci]
# [5.46.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.45.0...v5.46.0-dev.1) (2025-11-04)

### Features

* **YouTube - Hide layout components:** Add "Hide Hype points" ([#6230](https://github.com/ReVanced/revanced-patches/issues/6230)) ([a52c015](a52c0153b1))
* **YouTube - Hide player flyout menu items:** Add "Hide Listen with YouTube Music" ([#6232](https://github.com/ReVanced/revanced-patches/issues/6232)) ([858edbf](858edbf3e7))
2025-11-04 07:10:24 +00:00
ILoveOpenSourceApplications
858edbf3e7 feat(YouTube - Hide player flyout menu items): Add "Hide Listen with YouTube Music" (#6232) 2025-11-04 09:07:11 +02:00
ILoveOpenSourceApplications
a52c0153b1 feat(YouTube - Hide layout components): Add "Hide Hype points" (#6230) 2025-11-04 09:05:28 +02:00
semantic-release-bot
cd9ef81354 chore: Release v5.45.0 [skip ci]
# [5.45.0](https://github.com/ReVanced/revanced-patches/compare/v5.44.0...v5.45.0) (2025-11-01)

### Bug Fixes

* **Instagram:** Update failing fingerprints on newer versions ([#6181](https://github.com/ReVanced/revanced-patches/issues/6181)) ([c73a03c](c73a03c9e1))
* **TikTok - Downloads:** Fix download path setting  ([#6191](https://github.com/ReVanced/revanced-patches/issues/6191)) ([3e4990a](3e4990afff))
* **YouTube - Change header:** Do not mirror header graphic with RTL languages ([a0c5604](a0c5604951))
* **YouTube - Force original audio:** Fall back to visionOS and not Android Studio if Android VR is not available ([6d01863](6d01863ec7))
* **YouTube - Spoof video streams:** Remove spoof stream audio selector that no longer works ([292fae4](292fae440c))
* **YouTube Music - Hide category bar:** Correctly hide the category bar in newer app targets ([#6175](https://github.com/ReVanced/revanced-patches/issues/6175)) ([13cf172](13cf1724bf))

### Features

* **Spoof video streams:** Add experimental "Android No SDK" client type ([5f23bfe](5f23bfe833))
* **TikTok:** Add `Sanitize sharing links` patch ([#6176](https://github.com/ReVanced/revanced-patches/issues/6176)) ([ef44eaa](ef44eaa119))
* **YouTube - Change Header:** Use SVG for header logo ([#6178](https://github.com/ReVanced/revanced-patches/issues/6178)) ([e9f45ce](e9f45ce926))
2025-11-01 15:36:32 +00:00
LisoUseInAIKyrios
1b2cd64a86 chore: Merge branch dev to main (#6174) 2025-11-01 16:32:23 +01:00
semantic-release-bot
0c03599f07 chore: Release v5.45.0-dev.6 [skip ci]
# [5.45.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.5...v5.45.0-dev.6) (2025-11-01)

### Features

* **Spoof video streams:** Add experimental "Android No SDK" client type ([5f23bfe](5f23bfe833))
2025-11-01 08:25:19 +00:00
LisoUseInAIKyrios
5f23bfe833 feat(Spoof video streams): Add experimental "Android No SDK" client type 2025-11-01 09:19:49 +01:00
github-actions[bot]
2cf8f0e636 chore: Sync translations (#6197) 2025-11-01 09:17:01 +01:00
semantic-release-bot
c17cf98c7e chore: Release v5.45.0-dev.5 [skip ci]
# [5.45.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.4...v5.45.0-dev.5) (2025-11-01)

### Bug Fixes

* **TikTok - Downloads:** Fix download path setting  ([#6191](https://github.com/ReVanced/revanced-patches/issues/6191)) ([3e4990a](3e4990afff))
* **YouTube - Spoof video streams:** Remove spoof stream audio selector that no longer works ([292fae4](292fae440c))
2025-11-01 07:36:49 +00:00
hxreborn
3e4990afff fix(TikTok - Downloads): Fix download path setting (#6191) 2025-11-01 08:32:26 +01:00
LisoUseInAIKyrios
292fae440c fix(YouTube - Spoof video streams): Remove spoof stream audio selector that no longer works 2025-11-01 08:31:17 +01:00
semantic-release-bot
12e7c0943a chore: Release v5.45.0-dev.4 [skip ci]
# [5.45.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.3...v5.45.0-dev.4) (2025-10-30)

### Bug Fixes

* **YouTube - Change header:** Do not mirror header graphic with RTL languages ([a0c5604](a0c5604951))
2025-10-30 08:32:28 +00:00
LisoUseInAIKyrios
a0c5604951 fix(YouTube - Change header): Do not mirror header graphic with RTL languages 2025-10-30 09:27:27 +01:00
LisoUseInAIKyrios
38d9299dfe chore: Add branding license text file (#6179) 2025-10-30 09:26:18 +01:00
semantic-release-bot
dfdbbfa047 chore: Release v5.45.0-dev.3 [skip ci]
# [5.45.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.2...v5.45.0-dev.3) (2025-10-27)

### Features

* **YouTube - Change Header:** Use SVG for header logo ([#6178](https://github.com/ReVanced/revanced-patches/issues/6178)) ([e9f45ce](e9f45ce926))
2025-10-27 17:14:52 +00:00
MarcaD
e9f45ce926 feat(YouTube - Change Header): Use SVG for header logo (#6178)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-10-27 21:10:49 +04:00
semantic-release-bot
1b38b1a3c8 chore: Release v5.45.0-dev.2 [skip ci]
# [5.45.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.1...v5.45.0-dev.2) (2025-10-26)

### Bug Fixes

* **YouTube - Force original audio:** Fall back to visionOS and not Android Studio if Android VR is not available ([6d01863](6d01863ec7))
* **YouTube Music - Hide category bar:** Correctly hide the category bar in newer app targets ([#6175](https://github.com/ReVanced/revanced-patches/issues/6175)) ([13cf172](13cf1724bf))
2025-10-26 15:27:23 +00:00
MarcaD
13cf1724bf fix(YouTube Music - Hide category bar): Correctly hide the category bar in newer app targets (#6175) 2025-10-26 19:23:40 +04:00
LisoUseInAIKyrios
6d01863ec7 fix(YouTube - Force original audio): Fall back to visionOS and not Android Studio if Android VR is not available 2025-10-26 19:23:04 +04:00
semantic-release-bot
a32ed30b4c chore: Release v5.45.0-dev.1 [skip ci]
# [5.45.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.44.0...v5.45.0-dev.1) (2025-10-26)

### Bug Fixes

* **Instagram:** Update failing fingerprints on newer versions ([#6181](https://github.com/ReVanced/revanced-patches/issues/6181)) ([c73a03c](c73a03c9e1))

### Features

* **TikTok:** Add `Sanitize sharing links` patch ([#6176](https://github.com/ReVanced/revanced-patches/issues/6176)) ([ef44eaa](ef44eaa119))
2025-10-26 10:05:58 +00:00
hxreborn
ef44eaa119 feat(TikTok): Add Sanitize sharing links patch (#6176) 2025-10-26 14:01:32 +04:00
rospino74
c73a03c9e1 fix(Instagram): Update failing fingerprints on newer versions (#6181) 2025-10-26 11:01:06 +01:00
LisoUseInAIKyrios
c1681f982a chore: Dump api 2025-10-25 08:11:57 +04:00
semantic-release-bot
1502bf7524 chore: Release v5.44.0 [skip ci]
# [5.44.0](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.44.0) (2025-10-24)

### Bug Fixes

* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](754b71959a))
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](0af8c8a766))
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](cfd244b408))
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](2e4c6fdcad))

### Features

* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](e7336d2ef3))
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](08baa19b4a))
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](591e106098))
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](de97562c5d))
2025-10-24 12:03:24 +00:00
LisoUseInAIKyrios
dffb1e6525 chore: Merge branch dev to main (#6135) 2025-10-24 15:59:21 +04:00
semantic-release-bot
b8c2ede2bf chore: Release v5.44.0-dev.4 [skip ci]
# [5.44.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.3...v5.44.0-dev.4) (2025-10-24)

### Features

* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](e7336d2ef3))
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](591e106098))
2025-10-24 05:32:12 +00:00
hckrman101
591e106098 feat(Duolingo): Add Skip energy recharge ads patch (#6167) 2025-10-24 09:28:34 +04:00
Pawloland
e7336d2ef3 feat: Add Custom network security patch (#6151) 2025-10-24 09:27:12 +04:00
LisoUseInAIKyrios
7a53f8f62d chore(YouTube Music): Simplify fingerprint for upcoming app versions 2025-10-24 09:25:44 +04:00
github-actions[bot]
3466d9d210 chore: Sync translations (#6172) 2025-10-24 09:19:08 +04:00
LisoUseInAIKyrios
876d7a6b03 chore(X / Twitter - Change link sharing domain): Add disclaimer to description 2025-10-24 09:18:20 +04:00
semantic-release-bot
a2aa9cac27 chore: Release v5.44.0-dev.3 [skip ci]
# [5.44.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.2...v5.44.0-dev.3) (2025-10-22)

### Features

* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](08baa19b4a))
2025-10-22 20:24:37 +00:00
LisoUseInAIKyrios
08baa19b4a feat(Duolingo - Enable debug menu): Support latest app target (#6163) 2025-10-23 00:21:30 +04:00
semantic-release-bot
7283b93cea chore: Release v5.44.0-dev.2 [skip ci]
# [5.44.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.1...v5.44.0-dev.2) (2025-10-22)

### Bug Fixes

* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](754b71959a))
2025-10-22 16:53:15 +00:00
Lassie111
754b71959a fix(Google Photos - Spoof features): Add support for Pixel 10 devices (#6161) 2025-10-22 20:50:10 +04:00
LisoUseInAIKyrios
c64e29ec57 refactor(YouTube - Seekbar): Remove obsolete splash screen color code 2025-10-22 11:47:39 +04:00
semantic-release-bot
b2dd008aee chore: Release v5.44.0-dev.1 [skip ci]
# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)

### Features

* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](de97562c5d))
2025-10-22 06:14:00 +00:00
rospino74
de97562c5d feat(Samsung Radio): Add Disable device checks patch (#6145) 2025-10-22 10:09:34 +04:00
semantic-release-bot
6373829fd6 chore: Release v5.43.2-dev.3 [skip ci]
## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)

### Bug Fixes

* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](cfd244b408))
2025-10-19 14:29:38 +00:00
Bceez
cfd244b408 fix(YouTube - Hide layout components): Hide new kind of community post (#6146) 2025-10-19 18:24:45 +04:00
semantic-release-bot
e8e28e2b6a chore: Release v5.43.2-dev.2 [skip ci]
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)

### Bug Fixes

* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](2e4c6fdcad))
2025-10-17 21:15:51 +00:00
LisoUseInAIKyrios
2e4c6fdcad fix(YouTube Music): Resolve patching 7.29 target 2025-10-18 01:12:34 +04:00
github-actions[bot]
644d6dcb51 chore: Sync translations (#6142) 2025-10-18 01:08:27 +04:00
semantic-release-bot
14dd7346a8 chore: Release v5.43.2-dev.1 [skip ci]
## [5.43.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.43.2-dev.1) (2025-10-16)

### Bug Fixes

* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](0af8c8a766))
2025-10-16 19:37:32 +00:00
ADudeCalledLeo
0af8c8a766 fix(X / Twitter - Change link sharing domain): Use bytecode patching to resolve patching with Manager (#6125) 2025-10-16 23:29:01 +04:00
semantic-release-bot
96454c843b chore: Release v5.43.1 [skip ci]
## [5.43.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1) (2025-10-15)

### Bug Fixes

* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](7563990750))
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](2a1e31860f))
2025-10-15 08:15:15 +00:00
LisoUseInAIKyrios
476ef0fae1 chore: Merge branch dev to main (#6121) 2025-10-15 12:12:25 +04:00
github-actions[bot]
bbec724afb chore: Sync translations (#6124) 2025-10-15 12:11:47 +04:00
semantic-release-bot
7a1dcbd4ee chore: Release v5.43.1-dev.2 [skip ci]
## [5.43.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.1-dev.1...v5.43.1-dev.2) (2025-10-14)

### Bug Fixes

* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](2a1e31860f))
2025-10-14 19:47:15 +00:00
LisoUseInAIKyrios
2a1e31860f fix(X / Twitter): Do not crash Manager when clicking on domain patch option 2025-10-14 23:42:15 +04:00
semantic-release-bot
949d6bdd19 chore: Release v5.43.1-dev.1 [skip ci]
## [5.43.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1-dev.1) (2025-10-14)

### Bug Fixes

* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](7563990750))
2025-10-14 18:19:42 +00:00
ADudeCalledLeo
7563990750 fix(X / Twitter - Change link sharing domain): Resolve duplicate patch option (#6119) 2025-10-14 22:16:01 +04:00
semantic-release-bot
4b605eb270 chore: Release v5.43.0 [skip ci]
# [5.43.0](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.43.0) (2025-10-14)

### Bug Fixes

* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](95eee59a87))
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](be2b144cc9))
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](54846253d7))
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](6555f6e6f8))
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](10ea250d4a))
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](0c19dbaf30))

### Features

* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](50f0b9c5ee))
2025-10-14 12:03:58 +00:00
LisoUseInAIKyrios
c2d7a7fb8b chore: Merge branch dev to main (#6090) 2025-10-14 16:00:00 +04:00
github-actions[bot]
a55560dc25 chore: Sync translations (#6118) 2025-10-14 15:58:38 +04:00
181 changed files with 2117 additions and 1436 deletions

View File

@@ -1,3 +1,186 @@
# [5.46.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.45.0...v5.46.0-dev.1) (2025-11-04)
### Features
* **YouTube - Hide layout components:** Add "Hide Hype points" ([#6230](https://github.com/ReVanced/revanced-patches/issues/6230)) ([a52c015](https://github.com/ReVanced/revanced-patches/commit/a52c0153b12c3f6f0ad260e03d2e9850c0466392))
* **YouTube - Hide player flyout menu items:** Add "Hide Listen with YouTube Music" ([#6232](https://github.com/ReVanced/revanced-patches/issues/6232)) ([858edbf](https://github.com/ReVanced/revanced-patches/commit/858edbf3e7f394fcc766d767c8dc54cf5ba24370))
# [5.45.0](https://github.com/ReVanced/revanced-patches/compare/v5.44.0...v5.45.0) (2025-11-01)
### Bug Fixes
* **Instagram:** Update failing fingerprints on newer versions ([#6181](https://github.com/ReVanced/revanced-patches/issues/6181)) ([c73a03c](https://github.com/ReVanced/revanced-patches/commit/c73a03c9e18a12262939c974cdf16221221d1487))
* **TikTok - Downloads:** Fix download path setting ([#6191](https://github.com/ReVanced/revanced-patches/issues/6191)) ([3e4990a](https://github.com/ReVanced/revanced-patches/commit/3e4990afff4c86b93970b153db713ad0f813124d))
* **YouTube - Change header:** Do not mirror header graphic with RTL languages ([a0c5604](https://github.com/ReVanced/revanced-patches/commit/a0c56049510ce040e1ccd49257864672c343344d))
* **YouTube - Force original audio:** Fall back to visionOS and not Android Studio if Android VR is not available ([6d01863](https://github.com/ReVanced/revanced-patches/commit/6d01863ec70617d9abc864ce6686ed9764dd151d))
* **YouTube - Spoof video streams:** Remove spoof stream audio selector that no longer works ([292fae4](https://github.com/ReVanced/revanced-patches/commit/292fae440c6d5694c5e84407becec2d91f1fd156))
* **YouTube Music - Hide category bar:** Correctly hide the category bar in newer app targets ([#6175](https://github.com/ReVanced/revanced-patches/issues/6175)) ([13cf172](https://github.com/ReVanced/revanced-patches/commit/13cf1724bf2f946c7129cab0db96721c90f9fe89))
### Features
* **Spoof video streams:** Add experimental "Android No SDK" client type ([5f23bfe](https://github.com/ReVanced/revanced-patches/commit/5f23bfe833c6e01617a7dbc5325b4a3fb931e53e))
* **TikTok:** Add `Sanitize sharing links` patch ([#6176](https://github.com/ReVanced/revanced-patches/issues/6176)) ([ef44eaa](https://github.com/ReVanced/revanced-patches/commit/ef44eaa119b9d6c5faec051e22d20f883d0da4f1))
* **YouTube - Change Header:** Use SVG for header logo ([#6178](https://github.com/ReVanced/revanced-patches/issues/6178)) ([e9f45ce](https://github.com/ReVanced/revanced-patches/commit/e9f45ce92695d5857473ff71c14b190bded28a73))
# [5.45.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.5...v5.45.0-dev.6) (2025-11-01)
### Features
* **Spoof video streams:** Add experimental "Android No SDK" client type ([5f23bfe](https://github.com/ReVanced/revanced-patches/commit/5f23bfe833c6e01617a7dbc5325b4a3fb931e53e))
# [5.45.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.4...v5.45.0-dev.5) (2025-11-01)
### Bug Fixes
* **TikTok - Downloads:** Fix download path setting ([#6191](https://github.com/ReVanced/revanced-patches/issues/6191)) ([3e4990a](https://github.com/ReVanced/revanced-patches/commit/3e4990afff4c86b93970b153db713ad0f813124d))
* **YouTube - Spoof video streams:** Remove spoof stream audio selector that no longer works ([292fae4](https://github.com/ReVanced/revanced-patches/commit/292fae440c6d5694c5e84407becec2d91f1fd156))
# [5.45.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.3...v5.45.0-dev.4) (2025-10-30)
### Bug Fixes
* **YouTube - Change header:** Do not mirror header graphic with RTL languages ([a0c5604](https://github.com/ReVanced/revanced-patches/commit/a0c56049510ce040e1ccd49257864672c343344d))
# [5.45.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.2...v5.45.0-dev.3) (2025-10-27)
### Features
* **YouTube - Change Header:** Use SVG for header logo ([#6178](https://github.com/ReVanced/revanced-patches/issues/6178)) ([e9f45ce](https://github.com/ReVanced/revanced-patches/commit/e9f45ce92695d5857473ff71c14b190bded28a73))
# [5.45.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.1...v5.45.0-dev.2) (2025-10-26)
### Bug Fixes
* **YouTube - Force original audio:** Fall back to visionOS and not Android Studio if Android VR is not available ([6d01863](https://github.com/ReVanced/revanced-patches/commit/6d01863ec70617d9abc864ce6686ed9764dd151d))
* **YouTube Music - Hide category bar:** Correctly hide the category bar in newer app targets ([#6175](https://github.com/ReVanced/revanced-patches/issues/6175)) ([13cf172](https://github.com/ReVanced/revanced-patches/commit/13cf1724bf2f946c7129cab0db96721c90f9fe89))
# [5.45.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.44.0...v5.45.0-dev.1) (2025-10-26)
### Bug Fixes
* **Instagram:** Update failing fingerprints on newer versions ([#6181](https://github.com/ReVanced/revanced-patches/issues/6181)) ([c73a03c](https://github.com/ReVanced/revanced-patches/commit/c73a03c9e18a12262939c974cdf16221221d1487))
### Features
* **TikTok:** Add `Sanitize sharing links` patch ([#6176](https://github.com/ReVanced/revanced-patches/issues/6176)) ([ef44eaa](https://github.com/ReVanced/revanced-patches/commit/ef44eaa119b9d6c5faec051e22d20f883d0da4f1))
# [5.44.0](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.44.0) (2025-10-24)
### Bug Fixes
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
### Features
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
# [5.44.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.3...v5.44.0-dev.4) (2025-10-24)
### Features
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
# [5.44.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.2...v5.44.0-dev.3) (2025-10-22)
### Features
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
# [5.44.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.1...v5.44.0-dev.2) (2025-10-22)
### Bug Fixes
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)
### Features
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)
### Bug Fixes
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)
### Bug Fixes
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
## [5.43.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.43.2-dev.1) (2025-10-16)
### Bug Fixes
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
## [5.43.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1) (2025-10-15)
### Bug Fixes
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
## [5.43.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.1-dev.1...v5.43.1-dev.2) (2025-10-14)
### Bug Fixes
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
## [5.43.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1-dev.1) (2025-10-14)
### Bug Fixes
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
# [5.43.0](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.43.0) (2025-10-14)
### Bug Fixes
* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d))
* **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))
* **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))
* **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))
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3))
### Features
* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b))
# [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14) # [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14)

View File

@@ -19,6 +19,6 @@ public class HideCastButtonPatch {
* Injection point * Injection point
*/ */
public static void hideCastButton(View view) { public static void hideCastButton(View view) {
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view); hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON, view);
} }
} }

View File

@@ -1,5 +1,8 @@
package app.revanced.extension.music.patches; package app.revanced.extension.music.patches;
import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition;
import android.view.View;
import app.revanced.extension.music.settings.Settings; import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@@ -8,7 +11,7 @@ public class HideCategoryBarPatch {
/** /**
* Injection point * Injection point
*/ */
public static boolean hideCategoryBar() { public static void hideCategoryBar(View view) {
return Settings.HIDE_CATEGORY_BAR.get(); hideViewBy0dpUnderCondition(Settings.HIDE_CATEGORY_BAR, view);
} }
} }

View File

@@ -1,6 +1,7 @@
package app.revanced.extension.music.patches.spoof; package app.revanced.extension.music.patches.spoof;
import static app.revanced.extension.music.settings.Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE; import static app.revanced.extension.music.settings.Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_NO_SDK;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS; import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
@@ -18,8 +19,9 @@ public class SpoofVideoStreamsPatch {
public static void setClientOrderToUse() { public static void setClientOrderToUse() {
List<ClientType> availableClients = List.of( List<ClientType> availableClients = List.of(
ANDROID_VR_1_43_32, ANDROID_VR_1_43_32,
ANDROID_VR_1_61_48, ANDROID_NO_SDK,
VISIONOS VISIONOS,
ANDROID_VR_1_61_48
); );
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse( app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(

View File

@@ -0,0 +1,4 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
compileOnly(project(":extensions:samsung:radio:stub"))
}

View File

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

View File

@@ -0,0 +1,24 @@
package app.revanced.extension.samsung.radio.misc.fix.crash;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SuppressWarnings("unused")
public final class FixCrashPatch {
/**
* Injection point.
* <p>
* Add the required permissions to the request list to avoid crashes on API 34+.
**/
public static final String[] fixPermissionRequestList(String[] perms) {
List<String> permsList = new ArrayList<>(Arrays.asList(perms));
if (permsList.contains("android.permission.POST_NOTIFICATIONS")) {
permsList.addAll(Arrays.asList("android.permission.RECORD_AUDIO", "android.permission.READ_PHONE_STATE", "android.permission.FOREGROUND_SERVICE_MICROPHONE"));
}
if (permsList.contains("android.permission.RECORD_AUDIO")) {
permsList.add("android.permission.FOREGROUND_SERVICE_MICROPHONE");
}
return permsList.toArray(new String[0]);
}
}

View File

@@ -0,0 +1,19 @@
package app.revanced.extension.samsung.radio.restrictions.device;
import android.os.SemSystemProperties;
import java.util.Arrays;
@SuppressWarnings("unused")
public final class BypassDeviceChecksPatch {
/**
* Injection point.
* <p>
* Check if the device has the required hardware
**/
public static final boolean checkIfDeviceIsIncompatible(String[] deviceList) {
String currentDevice = SemSystemProperties.getSalesCode();
return Arrays.asList(deviceList).contains(currentDevice);
}
}

View File

@@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "app.revanced.extension"
compileSdk = 34
defaultConfig {
minSdk = 24
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}

View File

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

View File

@@ -0,0 +1,7 @@
package android.os;
public class SemSystemProperties {
public static String getSalesCode() {
throw new UnsupportedOperationException("Stub");
}
}

View File

@@ -150,14 +150,14 @@ public class CustomBrandingPatch {
} }
for (ComponentName disable : componentsToDisable) { 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, pm.setComponentEnabledSetting(disable,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
} }
// Use info logging because if the alias status become corrupt the app cannot launch.
ComponentName componentToEnableFinal = componentToEnable; ComponentName componentToEnableFinal = componentToEnable;
Logger.printInfo(() -> "Enabling: " + componentToEnableFinal.getClassName()); Logger.printInfo(() -> "Enabling: " + componentToEnableFinal.getClassName());
pm.setComponentEnabledSetting(componentToEnable, pm.setComponentEnabledSetting(componentToEnable,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
} catch (Exception ex) { } catch (Exception ex) {

View File

@@ -17,9 +17,6 @@ public class LinkSanitizer {
public LinkSanitizer(String ... parametersToRemove) { public LinkSanitizer(String ... parametersToRemove) {
final int parameterCount = parametersToRemove.length; final int parameterCount = parametersToRemove.length;
if (parameterCount == 0) {
throw new IllegalArgumentException("No parameters specified");
}
// List is faster if only checking a few parameters. // List is faster if only checking a few parameters.
this.parametersToRemove = parameterCount > 4 this.parametersToRemove = parameterCount > 4
@@ -40,10 +37,12 @@ public class LinkSanitizer {
try { try {
Uri.Builder builder = uri.buildUpon().clearQuery(); Uri.Builder builder = uri.buildUpon().clearQuery();
for (String paramName : uri.getQueryParameterNames()) { if (!parametersToRemove.isEmpty()) {
if (!parametersToRemove.contains(paramName)) { for (String paramName : uri.getQueryParameterNames()) {
for (String value : uri.getQueryParameters(paramName)) { if (!parametersToRemove.contains(paramName)) {
builder.appendQueryParameter(paramName, value); for (String value : uri.getQueryParameters(paramName)) {
builder.appendQueryParameter(paramName, value);
}
} }
} }
} }

View File

@@ -4,7 +4,6 @@ import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.patches.CustomBrandingPatch.BrandingTheme; import static app.revanced.extension.shared.patches.CustomBrandingPatch.BrandingTheme;
import static app.revanced.extension.shared.settings.Setting.parent; import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
/** /**
* Settings shared across multiple apps. * Settings shared across multiple apps.
@@ -34,7 +33,6 @@ public class BaseSettings {
// //
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message"); public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS)); public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting SANITIZE_SHARED_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE); public static final BooleanSetting SANITIZE_SHARED_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE);

View File

@@ -54,6 +54,33 @@ public enum ClientType {
ANDROID_VR_1_61_48.supportsMultiAudioTracks, ANDROID_VR_1_61_48.supportsMultiAudioTracks,
"Android VR 1.43" "Android VR 1.43"
), ),
/**
* Video not playable: Paid / Movie / Private / Age-restricted.
* Note: The 'Authorization' key must be excluded from the header.
*
* According to TeamNewPipe in 2022, if the 'androidSdkVersion' field is missing,
* the GVS did not return a valid response:
* [NewPipe#8713 (comment)](https://github.com/TeamNewPipe/NewPipe/issues/8713#issuecomment-1207443550).
*
* According to the latest commit in yt-dlp, the GVS returns a valid response
* even if the 'androidSdkVersion' field is missing:
* [yt-dlp#14693](https://github.com/yt-dlp/yt-dlp/pull/14693).
*
* For some reason, PoToken is not required.
*/
ANDROID_NO_SDK(
3,
"ANDROID",
"",
"",
"",
Build.VERSION.RELEASE,
"20.05.46",
"com.google.android.youtube/20.05.46 (Linux; U; Android " + Build.VERSION.RELEASE + ") gzip",
false,
true,
"Android No SDK"
),
/** /**
* Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children". * Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children".
* <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a> * <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a>

View File

@@ -14,19 +14,11 @@ import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.AppLanguage; import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest; import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class SpoofVideoStreamsPatch { public class SpoofVideoStreamsPatch {
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
}
}
/** /**
* Domain used for internet connectivity verification. * Domain used for internet connectivity verification.
* It has an empty response body and is only used to check for a 204 response code. * It has an empty response body and is only used to check for a 204 response code.
@@ -62,8 +54,7 @@ public class SpoofVideoStreamsPatch {
} }
/** /**
* @param language Language override for non-authenticated requests. If this is null then * @param language Language override for non-authenticated requests.
* {@link BaseSettings#SPOOF_VIDEO_STREAMS_LANGUAGE} is used.
*/ */
public static void setLanguageOverride(@Nullable AppLanguage language) { public static void setLanguageOverride(@Nullable AppLanguage language) {
languageOverride = language; languageOverride = language;

View File

@@ -1,7 +1,5 @@
package app.revanced.extension.shared.spoof.requests; package app.revanced.extension.shared.spoof.requests;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -13,7 +11,6 @@ import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.requests.Requester; import app.revanced.extension.shared.requests.Requester;
import app.revanced.extension.shared.requests.Route; import app.revanced.extension.shared.requests.Route;
import app.revanced.extension.shared.settings.AppLanguage; import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch; import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
@@ -44,7 +41,7 @@ final class PlayerRoutes {
AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride(); AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride();
if (language == null) { if (language == null) {
// Force original audio has not overrode the language. // Force original audio has not overrode the language.
language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get(); language = AppLanguage.DEFAULT;
} }
//noinspection ExtractMethodRecommender //noinspection ExtractMethodRecommender
Locale streamLocale = language.getLocale(); Locale streamLocale = language.getLocale();

View File

@@ -23,6 +23,12 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
public void addPreferences(Context context) { public void addPreferences(Context context) {
addPreference(new ReVancedTikTokAboutPreference(context)); addPreference(new ReVancedTikTokAboutPreference(context));
addPreference(new TogglePreference(context,
"Sanitize sharing links",
"Remove tracking parameters from shared links.",
BaseSettings.SANITIZE_SHARED_LINKS
));
addPreference(new TogglePreference(context, addPreference(new TogglePreference(context,
"Enable debug log", "Enable debug log",
"Show extension debug log.", "Show extension debug log.",

View File

@@ -0,0 +1,29 @@
package app.revanced.extension.tiktok.share;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.privacy.LinkSanitizer;
import app.revanced.extension.shared.settings.BaseSettings;
@SuppressWarnings("unused")
public final class ShareUrlSanitizer {
private static final LinkSanitizer sanitizer = new LinkSanitizer();
/**
* Injection point for setting check.
*/
public static boolean shouldSanitize() {
return BaseSettings.SANITIZE_SHARED_LINKS.get();
}
/**
* Injection point for URL sanitization.
*/
public static String sanitizeShareUrl(final String url) {
if (url == null || url.isEmpty()) {
return url;
}
return sanitizer.sanitizeUrlString(url);
}
}

View File

@@ -2,7 +2,7 @@ package app.revanced.twitter.patches.links;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class ChangeLinkSharingDomainPatch { public final class ChangeLinkSharingDomainPatch {
private static final String LINK_FORMAT = "%s/%s/status/%s"; private static final String LINK_FORMAT = "https://%s/%s/status/%s";
/** /**
* Method is modified during patching. Do not change. * Method is modified during patching. Do not change.
@@ -11,6 +11,16 @@ public final class ChangeLinkSharingDomainPatch {
return ""; return "";
} }
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
/**
* Injection point.
*/
public static String formatResourceLink(Object... formatArgs) {
String username = (String) formatArgs[0];
String tweetId = (String) formatArgs[1];
return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
}
/** /**
* Injection point. * Injection point.
*/ */

View File

@@ -17,15 +17,25 @@ public class ChangeHeaderPatch {
DEFAULT(null, null), DEFAULT(null, null),
REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"), REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"),
PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"), PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"),
REVANCED("revanced_header_logo", "revanced_header_logo"), ROUNDED("revanced_header_rounded"),
REVANCED_MINIMAL("revanced_header_logo_minimal", "revanced_header_logo_minimal"), MINIMAL("revanced_header_minimal"),
CUSTOM("custom_header", "custom_header"); CUSTOM("revanced_header_custom"),
// Old enum names for data migration. TODO: Eventually delete these.
@Deprecated
REVANCED(ROUNDED.attributeName),
@Deprecated
REVANCED_MINIMAL(MINIMAL.attributeName);
@Nullable @Nullable
private final String attributeName; private final String attributeName;
@Nullable @Nullable
private final String drawableName; private final String drawableName;
HeaderLogo(String attributeName) {
this(Objects.requireNonNull(attributeName), Objects.requireNonNull(attributeName));
}
HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) { HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) {
this.attributeName = attributeName; this.attributeName = attributeName;
this.drawableName = drawableName; this.drawableName = drawableName;
@@ -42,9 +52,8 @@ public class ChangeHeaderPatch {
final int identifier = Utils.getResourceIdentifier(attributeName, "attr"); final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
if (identifier == 0) { if (identifier == 0) {
// Identifier is zero if custom header setting was included in imported settings // Should never happen.
// and a custom image was not included during patching. Logger.printException(() -> "Could not find attribute: " + drawableName);
Logger.printDebug(() -> "Could not find attribute: " + drawableName);
Settings.HEADER_LOGO.resetToDefault(); Settings.HEADER_LOGO.resetToDefault();
return null; return null;
} }
@@ -63,12 +72,14 @@ public class ChangeHeaderPatch {
: "_light"); : "_light");
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable"); final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
if (identifier == 0) { if (identifier != 0) {
Logger.printDebug(() -> "Could not find drawable: " + drawableFullName); return Utils.getContext().getDrawable(identifier);
Settings.HEADER_LOGO.resetToDefault();
return null;
} }
return Utils.getContext().getDrawable(identifier);
// Should never happen.
Logger.printException(() -> "Could not find drawable: " + drawableFullName);
Settings.HEADER_LOGO.resetToDefault();
return null;
} }
} }

View File

@@ -63,6 +63,11 @@ final class DescriptionComponentsFilter extends Filter {
"how_this_was_made_section" "how_this_was_made_section"
); );
final StringFilterGroup hypePoints = new StringFilterGroup(
Settings.HIDE_HYPE_POINTS,
"hype_points_factoid"
);
macroMarkersCarousel = new StringFilterGroup( macroMarkersCarousel = new StringFilterGroup(
null, null,
"macro_markers_carousel.e" "macro_markers_carousel.e"
@@ -96,6 +101,7 @@ final class DescriptionComponentsFilter extends Filter {
infoCardsSection, infoCardsSection,
horizontalShelf, horizontalShelf,
howThisWasMadeSection, howThisWasMadeSection,
hypePoints,
macroMarkersCarousel, macroMarkersCarousel,
podcastSection, podcastSection,
transcriptSection transcriptSection

View File

@@ -87,7 +87,8 @@ public final class LayoutComponentsFilter extends Filter {
"post_shelf_slim.e", "post_shelf_slim.e",
"videos_post_responsive_root.e", "videos_post_responsive_root.e",
"text_post_responsive_root.e", "text_post_responsive_root.e",
"poll_post_responsive_root.e" "poll_post_responsive_root.e",
"shared_post_root.e"
); );
final var subscribersCommunityGuidelines = new StringFilterGroup( final var subscribersCommunityGuidelines = new StringFilterGroup(

View File

@@ -63,12 +63,12 @@ public class PlayerFlyoutMenuItemsFilter extends Filter {
"volume_stable_" "volume_stable_"
), ),
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_PLAYER_FLYOUT_HELP, Settings.HIDE_PLAYER_FLYOUT_LISTEN_WITH_YOUTUBE_MUSIC,
"yt_outline_question_circle_" "yt_outline_youtube_music_"
), ),
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_PLAYER_FLYOUT_MORE_INFO, Settings.HIDE_PLAYER_FLYOUT_HELP,
"yt_outline_info_circle_" "yt_outline_question_circle_"
), ),
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_PLAYER_FLYOUT_LOCK_SCREEN, Settings.HIDE_PLAYER_FLYOUT_LOCK_SCREEN,

View File

@@ -1,6 +1,7 @@
package app.revanced.extension.youtube.patches.spoof; package app.revanced.extension.youtube.patches.spoof;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_NO_SDK;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48; import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
import static app.revanced.extension.shared.spoof.ClientType.IPADOS; import static app.revanced.extension.shared.spoof.ClientType.IPADOS;
@@ -38,9 +39,10 @@ public class SpoofVideoStreamsPatch {
} }
List<ClientType> availableClients = List.of( List<ClientType> availableClients = List.of(
VISIONOS,
ANDROID_CREATOR, ANDROID_CREATOR,
ANDROID_VR_1_43_32, ANDROID_VR_1_43_32,
VISIONOS, ANDROID_NO_SDK,
IPADOS); IPADOS);
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse( app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(

View File

@@ -1,51 +0,0 @@
package app.revanced.extension.youtube.patches.theme;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.youtube.patches.HideSeekbarPatch;
import app.revanced.extension.youtube.settings.Settings;
/**
* Used by {@link SeekbarColorPatch} change the color of the seekbar.
* and {@link HideSeekbarPatch} to hide the seekbar of the feed and watch history.
*/
@SuppressWarnings("unused")
public class ProgressBarDrawable extends Drawable {
private final Paint paint = new Paint();
{
paint.setColor(SeekbarColorPatch.getSeekbarColor());
}
@Override
public void draw(@NonNull Canvas canvas) {
if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) {
return;
}
canvas.drawRect(getBounds(), paint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}

View File

@@ -4,9 +4,7 @@ import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.clamp; import static app.revanced.extension.shared.Utils.clamp;
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle; import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.AnimatedVectorDrawable;
import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieAnimationView;
@@ -15,7 +13,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
import java.util.Scanner; import java.util.Scanner;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
@@ -104,27 +101,6 @@ public final class SeekbarColorPatch {
return customSeekbarColor; return customSeekbarColor;
} }
private static int colorChannelTo3Bits(int channel8Bits) {
final float channel3Bits = channel8Bits * 7 / 255f;
// If a color channel is near zero, then allow rounding up so values between
// 0x12 and 0x23 will show as 0x24. But always round down when the channel is
// near full saturation, otherwise rounding to nearest will cause all values
// between 0xEC and 0xFE to always show as full saturation (0xFF).
return channel3Bits < 6
? Math.round(channel3Bits)
: (int) channel3Bits;
}
@SuppressWarnings("SameParameterValue")
private static String get9BitStyleIdentifier(int color24Bit) {
final int r3 = colorChannelTo3Bits(Color.red(color24Bit));
final int g3 = colorChannelTo3Bits(Color.green(color24Bit));
final int b3 = colorChannelTo3Bits(Color.blue(color24Bit));
return String.format(Locale.US, "splash_seekbar_color_style_%d_%d_%d", r3, g3, b3);
}
/** /**
* injection point. * injection point.
*/ */
@@ -135,36 +111,6 @@ public final class SeekbarColorPatch {
return original; // false = drawable style, true = lottie style. return original; // false = drawable style, true = lottie style.
} }
/**
* Injection point.
* Old drawable style launch screen.
*/
public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vectorDrawable) {
// Alternatively a ColorMatrixColorFilter can be used to change the color of the drawable
// without using any styles, but a color filter cannot selectively change the seekbar
// while keeping the red YT logo untouched.
// Even if the seekbar color xml value is changed to a completely different color (such as green),
// a color filter still cannot be selectively applied when the drawable has more than 1 color.
try {
// Must set the color even if custom seekbar is off,
// because the xml color was replaced with a themed value.
String seekbarStyle = get9BitStyleIdentifier(customSeekbarColor);
Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle);
final int styleIdentifierDefault = Utils.getResourceIdentifierOrThrow(
seekbarStyle,
"style"
);
Resources.Theme theme = Utils.getContext().getResources().newTheme();
theme.applyStyle(styleIdentifierDefault, true);
vectorDrawable.applyTheme(theme);
} catch (Exception ex) {
Logger.printException(() -> "setSplashAnimationDrawableTheme failure", ex);
}
}
/** /**
* Injection point. * Injection point.
* Modern Lottie style animation. * Modern Lottie style animation.

View File

@@ -2,7 +2,6 @@ package app.revanced.extension.youtube.settings;
import static java.lang.Boolean.FALSE; import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.settings.Setting.migrateOldSettingToNew;
import static app.revanced.extension.shared.settings.Setting.parent; import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.settings.Setting.parentsAll; import static app.revanced.extension.shared.settings.Setting.parentsAll;
import static app.revanced.extension.shared.settings.Setting.parentsAny; import static app.revanced.extension.shared.settings.Setting.parentsAny;
@@ -17,7 +16,6 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerH
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideSubtextsAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideSubtextsAvailability;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType; import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability; import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability; import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
@@ -41,7 +39,6 @@ import app.revanced.extension.shared.settings.IntegerSetting;
import app.revanced.extension.shared.settings.LongSetting; import app.revanced.extension.shared.settings.LongSetting;
import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.settings.StringSetting; import app.revanced.extension.shared.settings.StringSetting;
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
@@ -214,6 +211,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE); public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE);
public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE); public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE);
public static final BooleanSetting HIDE_HOW_THIS_WAS_MADE_SECTION = new BooleanSetting("revanced_hide_how_this_was_made_section", FALSE); public static final BooleanSetting HIDE_HOW_THIS_WAS_MADE_SECTION = new BooleanSetting("revanced_hide_how_this_was_made_section", FALSE);
public static final BooleanSetting HIDE_HYPE_POINTS = new BooleanSetting("revanced_hide_hype_points", FALSE);
public static final BooleanSetting HIDE_INFO_CARDS_SECTION = new BooleanSetting("revanced_hide_info_cards_section", TRUE); public static final BooleanSetting HIDE_INFO_CARDS_SECTION = new BooleanSetting("revanced_hide_info_cards_section", TRUE);
public static final BooleanSetting HIDE_KEY_CONCEPTS_SECTION = new BooleanSetting("revanced_hide_key_concepts_section", FALSE); public static final BooleanSetting HIDE_KEY_CONCEPTS_SECTION = new BooleanSetting("revanced_hide_key_concepts_section", FALSE);
public static final BooleanSetting HIDE_PODCAST_SECTION = new BooleanSetting("revanced_hide_podcast_section", TRUE); public static final BooleanSetting HIDE_PODCAST_SECTION = new BooleanSetting("revanced_hide_podcast_section", TRUE);
@@ -242,9 +240,9 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_PLAYER_FLYOUT_AUDIO_TRACK = new BooleanSetting("revanced_hide_player_flyout_audio_track", FALSE, new HideAudioFlyoutMenuAvailability()); public static final BooleanSetting HIDE_PLAYER_FLYOUT_AUDIO_TRACK = new BooleanSetting("revanced_hide_player_flyout_audio_track", FALSE, new HideAudioFlyoutMenuAvailability());
public static final BooleanSetting HIDE_PLAYER_FLYOUT_CAPTIONS = new BooleanSetting("revanced_hide_player_flyout_captions", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_CAPTIONS = new BooleanSetting("revanced_hide_player_flyout_captions", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_HELP = new BooleanSetting("revanced_hide_player_flyout_help", TRUE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_HELP = new BooleanSetting("revanced_hide_player_flyout_help", TRUE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_LISTEN_WITH_YOUTUBE_MUSIC = new BooleanSetting("revanced_hide_player_flyout_listen_with_youtube_music", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOCK_SCREEN = new BooleanSetting("revanced_hide_player_flyout_lock_screen", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOCK_SCREEN = new BooleanSetting("revanced_hide_player_flyout_lock_screen", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOOP_VIDEO = new BooleanSetting("revanced_hide_player_flyout_loop_video", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_LOOP_VIDEO = new BooleanSetting("revanced_hide_player_flyout_loop_video", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_MORE_INFO = new BooleanSetting("revanced_hide_player_flyout_more_info", TRUE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_SLEEP_TIMER = new BooleanSetting("revanced_hide_player_flyout_sleep_timer", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_SLEEP_TIMER = new BooleanSetting("revanced_hide_player_flyout_sleep_timer", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_SPEED = new BooleanSetting("revanced_hide_player_flyout_speed", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_SPEED = new BooleanSetting("revanced_hide_player_flyout_speed", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_STABLE_VOLUME = new BooleanSetting("revanced_hide_player_flyout_stable_volume", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_STABLE_VOLUME = new BooleanSetting("revanced_hide_player_flyout_stable_volume", FALSE);
@@ -452,14 +450,7 @@ public class Settings extends BaseSettings {
public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFFFF", false, false); public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFFFF", false, false);
// Deprecated migrations // Deprecated migrations
private static final BooleanSetting DEPRECATED_AUTO_REPEAT = new BooleanSetting("revanced_auto_repeat", FALSE);
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true);
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE);
private static final IntegerSetting DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127);
private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033"); private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033");
private static final BooleanSetting DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE);
private static final BooleanSetting DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
private static final BooleanSetting DEPRECATED_AUTO_CAPTIONS = new BooleanSetting("revanced_auto_captions", FALSE);
private static final FloatSetting DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f, false, false); private static final FloatSetting DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f, false, false);
private static final FloatSetting DEPRECATED_SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f, false, false); private static final FloatSetting DEPRECATED_SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f, false, false);
@@ -475,17 +466,12 @@ public class Settings extends BaseSettings {
static { static {
// region Migration // region Migration
migrateOldSettingToNew(DEPRECATED_AUTO_REPEAT, LOOP_VIDEO); // Migrate renamed change header enums.
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS); if (HEADER_LOGO.get() == HeaderLogo.REVANCED) {
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER); HEADER_LOGO.save(HeaderLogo.ROUNDED);
migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO); }
migrateOldSettingToNew(DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU, ADVANCED_VIDEO_QUALITY_MENU); if (HEADER_LOGO.get() == HeaderLogo.REVANCED_MINIMAL) {
migrateOldSettingToNew(DEPRECATED_AUTO_CAPTIONS, DISABLE_AUTO_CAPTIONS); HEADER_LOGO.save(HeaderLogo.MINIMAL);
// Migrate renamed enum.
//noinspection deprecation
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {
MINIPLAYER_TYPE.save(MINIMAL);
} }
// Migrate old single color seekbar with a slightly brighter accent color based on the primary. // Migrate old single color seekbar with a slightly brighter accent color based on the primary.
@@ -512,11 +498,6 @@ public class Settings extends BaseSettings {
DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY.resetToDefault(); DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY.resetToDefault();
} }
if (!DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.isSetToDefault()) {
SWIPE_OVERLAY_OPACITY.save(DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.get() / 255);
DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.resetToDefault();
}
// Old spoof versions that no longer work, // Old spoof versions that no longer work,
// or is spoofing to a version the same or newer than this app. // or is spoofing to a version the same or newer than this app.
if (!SPOOF_APP_VERSION_TARGET.isSetToDefault() && if (!SPOOF_APP_VERSION_TARGET.isSetToDefault() &&
@@ -534,13 +515,7 @@ public class Settings extends BaseSettings {
// RYD requires manually migrating old settings since the lack of // RYD requires manually migrating old settings since the lack of
// a "revanced_" on the old setting causes duplicate key exceptions during export. // a "revanced_" on the old setting causes duplicate key exceptions during export.
SharedPrefCategory revancedPrefs = Setting.preferences; Setting.migrateFromOldPreferences(Setting.preferences, RYD_USER_ID, "ryd_user_id");
Setting.migrateFromOldPreferences(revancedPrefs, RYD_USER_ID, "ryd_user_id");
Setting.migrateFromOldPreferences(revancedPrefs, RYD_ENABLED, "ryd_enabled");
Setting.migrateFromOldPreferences(revancedPrefs, RYD_DISLIKE_PERCENTAGE, "ryd_dislike_percentage");
Setting.migrateFromOldPreferences(revancedPrefs, RYD_COMPACT_LAYOUT, "ryd_compact_layout");
Setting.migrateFromOldPreferences(revancedPrefs, RYD_ESTIMATED_LIKE, "ryd_estimated_like");
Setting.migrateFromOldPreferences(revancedPrefs, RYD_TOAST_ON_CONNECTION_ERROR, "ryd_toast_on_connection_error");
// Migrate old saved data. Must be done here before the settings can be used by any other code. // Migrate old saved data. Must be done here before the settings can be used by any other code.
applyOldSbOpacityToColor(SB_CATEGORY_SPONSOR_COLOR, DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY); applyOldSbOpacityToColor(SB_CATEGORY_SPONSOR_COLOR, DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY);

View File

@@ -1,63 +0,0 @@
package app.revanced.extension.youtube.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import android.content.Context;
import android.util.AttributeSet;
import app.revanced.extension.shared.settings.preference.SortedListPreference;
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 SpoofAudioSelectorListPreference extends SortedListPreference {
private final boolean available;
{
final boolean isAndroidStudio = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR;
if (isAndroidStudio || SpoofVideoStreamsPatch.getLanguageOverride() != null) {
available = false;
super.setEnabled(false);
super.setSummary(str(isAndroidStudio
? "revanced_spoof_video_streams_language_android_studio"
: "revanced_spoof_video_streams_language_not_available"));
} else {
available = true;
}
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SpoofAudioSelectorListPreference(Context context) {
super(context);
}
@Override
public void setEnabled(boolean enabled) {
if (!available) {
return;
}
super.setEnabled(enabled);
}
@Override
public void setSummary(CharSequence summary) {
if (!available) {
return;
}
super.setSummary(summary);
}
}

View File

@@ -80,29 +80,34 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
Logger.printDebug(() -> "Updating spoof stream side effects preference"); Logger.printDebug(() -> "Updating spoof stream side effects preference");
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get()); setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());
String summary = str("revanced_spoof_video_streams_about_no_audio_tracks"); String summary = "";
switch (clientType) { switch (clientType) {
case ANDROID_CREATOR -> case ANDROID_CREATOR ->
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume") summary = str("revanced_spoof_video_streams_about_no_audio_tracks")
+ '\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"); + '\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. // 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 -> case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 ->
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume"); summary = str("revanced_spoof_video_streams_about_no_audio_tracks")
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
case ANDROID_NO_SDK ->
summary = str("revanced_spoof_video_streams_about_playback_failure");
case IPADOS -> case IPADOS ->
summary = str("revanced_spoof_video_streams_about_playback_failure") summary = str("revanced_spoof_video_streams_about_playback_failure")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1"); + '\n' + str("revanced_spoof_video_streams_about_no_av1");
case VISIONOS -> case VISIONOS ->
summary = str("revanced_spoof_video_streams_about_experimental") summary = str("revanced_spoof_video_streams_about_experimental")
+ '\n' + summary + '\n' + str("revanced_spoof_video_streams_about_no_audio_tracks")
+ '\n' + str("revanced_spoof_video_streams_about_no_av1"); + '\n' + str("revanced_spoof_video_streams_about_no_av1");
default -> Logger.printException(() -> "Unknown client: " + clientType);
} }
// Only iPadOS can play children videos in incognito, but it commonly fails at 1 minute // Only iPadOS can play children videos in incognito, but it commonly fails at 1 minute
// or doesn't even start playback at all. List the side effect for other clients // or doesn't start playback at all. List the side effect for other clients
// since they will fall over to iPadOS. // since they will fall over to iPadOS.
if (clientType != ClientType.IPADOS) { if (clientType != ClientType.IPADOS && clientType != ClientType.ANDROID_NO_SDK) {
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos"); summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
} }

View File

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

View File

@@ -60,6 +60,10 @@ public final class app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWi
public static final fun getSpoofWifiPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSpoofWifiPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/all/misc/customcertificates/CustomCertificatesPatchKt {
public static final fun getCustomNetworkSecurityPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
}
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatchKt { public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatchKt {
public static final fun getEnableAndroidDebuggingPatch ()Lapp/revanced/patcher/patch/ResourcePatch; public static final fun getEnableAndroidDebuggingPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
} }
@@ -184,6 +188,10 @@ public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatchKt {
public static final fun getEnableDebugMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getEnableDebugMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatchKt {
public static final fun getSkipEnergyRechargeAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatchKt { public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatchKt {
public static final fun getHideSponsoredStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideSponsoredStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -481,7 +489,9 @@ public final class app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatc
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt { public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch; public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
public static final fun is_7_16_or_greater ()Z
public static final fun is_7_33_or_greater ()Z public static final fun is_7_33_or_greater ()Z
public static final fun is_8_05_or_greater ()Z
public static final fun is_8_10_or_greater ()Z public static final fun is_8_10_or_greater ()Z
public static final fun is_8_11_or_greater ()Z public static final fun is_8_11_or_greater ()Z
public static final fun is_8_15_or_greater ()Z public static final fun is_8_15_or_greater ()Z
@@ -762,6 +772,14 @@ public final class app/revanced/patches/reddit/misc/tracking/url/SanitizeUrlQuer
public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatchKt {
public static final fun getFixCrashPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatchKt {
public static final fun getBypassDeviceChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt { public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt {
public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -1170,6 +1188,10 @@ public final class app/revanced/patches/tiktok/misc/settings/SettingsPatchKt {
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatchKt {
public static final fun getSanitizeShareUrlsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt { public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt {
public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }

View File

@@ -0,0 +1,182 @@
package app.revanced.patches.all.misc.customcertificates
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringsOption
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.getNode
import org.w3c.dom.Element
import java.io.File
val customNetworkSecurityPatch = resourcePatch(
name = "Custom network security",
description = "Allows trusting custom certificate authorities for a specific domain.",
use = false
) {
val targetDomains by stringsOption(
key = "targetDomains",
title = "Target domains",
description = "List of domains to which the custom trust configuration will be applied (one domain per entry).",
default = listOf("example.com"),
required = true
)
val includeSubdomains by booleanOption(
key = "includeSubdomains",
title = "Include subdomains",
description = "Applies the configuration to all subdomains of the target domains.",
default = false,
required = true
)
val customCAFilePaths by stringsOption(
key = "customCAFilePaths",
title = "Custom CA file paths",
description = """
List of paths to files in PEM or DER format (one file path per entry).
Makes an app trust the provided custom certificate authorities (CAs),
for the specified domains, and if the option "Include Subdomains" is enabled then also the subdomains.
CA files will be bundled in res/raw/ of resulting APK
""".trimIndentMultiline(),
default = null,
required = false
)
val allowUserCerts by booleanOption(
key = "allowUserCerts",
title = "Trust user added CAs",
description = "Makes an app trust certificates from the Android user store for the specified domains, and if the option \"Include Subdomains\" is enabled then also the subdomains.",
default = false,
required = true
)
val allowSystemCerts by booleanOption(
key = "allowSystemCerts",
title = "Trust system CAs",
description = "Makes an app trust certificates from the Android system store for the specified domains, and and if the option \"Include Subdomains\" is enabled then also the subdomains.",
default = true,
required = true
)
val allowCleartextTraffic by booleanOption(
key = "allowCleartextTraffic",
title = "Allow cleartext traffic (HTTP)",
description = "Allows unencrypted HTTP traffic for the specified domains, and if \"Include Subdomains\" is enabled then also the subdomains.",
default = false,
required = true
)
val overridePins by booleanOption(
key = "overridePins",
title = "Override certificate pinning",
description = "Overrides certificate pinning for the specified domains and their subdomains if the option \"Include Subdomains\" is enabled to allow inspecting app traffic via a proxy.",
default = false,
required = true
)
fun generateNetworkSecurityConfig(): String {
val targetDomains = targetDomains ?: emptyList()
val includeSubdomains = includeSubdomains ?: false
val customCAFilePaths = customCAFilePaths ?: emptyList()
val allowUserCerts = allowUserCerts ?: false
val allowSystemCerts = allowSystemCerts ?: true
val allowCleartextTraffic = allowCleartextTraffic ?: false
val overridePins = overridePins ?: false
val domainsXML = buildString {
targetDomains.forEach {
appendLine(""" <domain includeSubdomains="$includeSubdomains">$it</domain>""")
}
}.trimEnd()
val trustAnchorsXML = buildString {
if (allowSystemCerts) {
appendLine(""" <certificates src="system" overridePins="$overridePins" />""")
}
if (allowUserCerts) {
appendLine(""" <certificates src="user" overridePins="$overridePins" />""")
}
customCAFilePaths.forEach { path ->
val fileName = path.substringAfterLast('/').substringBeforeLast('.')
appendLine(""" <certificates src="@raw/$fileName" overridePins="$overridePins" />""")
}
}
if (trustAnchorsXML.isBlank()) {
throw PatchException("At least one trust anchor (System, User, or Custom CA) must be enabled.")
}
return """
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="$allowCleartextTraffic">
$domainsXML
<trust-anchors>
${trustAnchorsXML.trimEnd()}
</trust-anchors>
</domain-config>
</network-security-config>
""".trimIndent()
}
execute {
val nscFileNameBare = "network_security_config"
val resXmlDir = "res/xml"
val resRawDir = "res/raw"
val nscFileNameWithSuffix = "$nscFileNameBare.xml"
document("AndroidManifest.xml").use { document ->
val applicationNode = document.getNode("application") as Element
applicationNode.setAttribute("android:networkSecurityConfig", "@xml/$nscFileNameBare")
}
File(get(resXmlDir), nscFileNameWithSuffix).apply {
writeText(generateNetworkSecurityConfig())
}
for (customCAFilePath in customCAFilePaths ?: emptyList()) {
val file = File(customCAFilePath)
if (!file.exists()) {
throw PatchException(
"The custom CA file path cannot be found: " +
file.absolutePath
)
}
if (!file.isFile) {
throw PatchException(
"The custom CA file path must be a file: "
+ file.absolutePath
)
}
val caFileNameWithoutSuffix = customCAFilePath.substringAfterLast('/').substringBefore('.')
val caFile = File(customCAFilePath)
File(
get(resRawDir),
caFileNameWithoutSuffix
).writeText(
caFile.readText()
)
}
}
}

View File

@@ -1,26 +1,35 @@
package app.revanced.patches.duolingo.debug package app.revanced.patches.duolingo.debug
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused") @Suppress("unused")
val enableDebugMenuPatch = bytecodePatch( val enableDebugMenuPatch = bytecodePatch(
name = "Enable debug menu", name = "Enable debug menu",
use = false, use = false
) { ) {
compatibleWith("com.duolingo"("5.158.4")) compatibleWith("com.duolingo")
execute { execute {
initializeBuildConfigProviderFingerprint.method.apply { // It seems all categories are allowed on release. Force this on anyway.
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex debugCategoryAllowOnReleaseBuildsFingerprint.method.returnEarly(true)
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructions( // Change build config debug build flag.
insertIndex, buildConfigProviderConstructorFingerprint.match(
"const/4 v$register, 0x1", buildConfigProviderToStringFingerprint.classDef
) ).let {
val index = it.patternMatch!!.startIndex
it.method.apply {
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction(
index + 1,
"const/4 v$register, 0x1"
)
}
} }
} }
} }

View File

@@ -4,16 +4,25 @@ import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
/** internal val debugCategoryAllowOnReleaseBuildsFingerprint = fingerprint {
* The `BuildConfigProvider` class has two booleans: returns("Z")
* parameters()
* - `isChina`: (usually) compares "play" with "china"...except for builds in China custom { method, classDef ->
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true` method.name == "getAllowOnReleaseBuilds" && classDef.type == "Lcom/duolingo/debug/DebugCategory;"
*/ }
}
internal val initializeBuildConfigProviderFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) internal val buildConfigProviderConstructorFingerprint = fingerprint {
returns("V") accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
opcodes(Opcode.IPUT_BOOLEAN) parameters()
strings("debug", "release", "china") opcodes(Opcode.CONST_4)
}
internal val buildConfigProviderToStringFingerprint = fingerprint {
parameters()
returns("Ljava/lang/String;")
strings("BuildConfigProvider(") // Partial string match.
custom { method, _ ->
method.name == "toString"
}
} }

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.duolingo.energy
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Matches the class found in [energyConfigToStringFingerprint].
*/
internal val initializeEnergyConfigFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
opcodes(Opcode.RETURN_VOID)
}
// Class name currently is not obfuscated but it may be in the future.
internal val energyConfigToStringFingerprint = fingerprint {
parameters()
returns("Ljava/lang/String;")
strings("EnergyConfig(", "maxEnergy=") // Partial string matches.
custom { method, _ -> method.name == "toString" }
}

View File

@@ -0,0 +1,31 @@
package app.revanced.patches.duolingo.energy
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.findFieldFromToString
@Suppress("unused")
val skipEnergyRechargeAdsPatch = bytecodePatch(
name = "Skip energy recharge ads",
description = "Skips watching ads to recharge energy."
) {
compatibleWith("com.duolingo")
execute {
initializeEnergyConfigFingerprint
.match(energyConfigToStringFingerprint.classDef)
.method.apply {
val energyField = energyConfigToStringFingerprint.method
.findFieldFromToString("energy=")
val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex
addInstructions(
insertIndex,
"""
const/16 v0, 99
iput v0, p0, $energyField
"""
)
}
}
}

View File

@@ -47,6 +47,7 @@ val spoofFeaturesPatch = bytecodePatch(
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE", "com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2024_EXPERIENCE", "com.google.android.feature.PIXEL_2024_EXPERIENCE",
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE", "com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2025_EXPERIENCE",
), ),
title = "Features to disable", title = "Features to disable",
description = "Google Pixel exclusive features to disable." + description = "Google Pixel exclusive features to disable." +

View File

@@ -3,9 +3,10 @@ package app.revanced.patches.instagram.hide.navigation
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
internal val initializeNavigationButtonsListFingerprint = fingerprint { internal val initializeNavigationButtonsListFingerprint = fingerprint {
strings("Nav3") accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Lcom/instagram/common/session/UserSession;", "Z") parameters("Lcom/instagram/common/session/UserSession;", "Z")
returns("Ljava/util/List;") returns("Ljava/util/List;")
} }

View File

@@ -24,7 +24,7 @@ val enableDeveloperMenuPatch = bytecodePatch(
with(clearNotificationReceiverFingerprint.method) { with(clearNotificationReceiverFingerprint.method) {
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) { indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) {
val reference = getReference<MethodReference>() val reference = getReference<MethodReference>()
Opcode.INVOKE_STATIC == opcode && opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
reference?.parameterTypes?.size == 1 && reference?.parameterTypes?.size == 1 &&
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" && reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
reference.returnType == "Z" reference.returnType == "Z"

View File

@@ -1,20 +1,16 @@
package app.revanced.patches.music.layout.compactheader package app.revanced.patches.music.layout.compactheader
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.literal
internal val constructCategoryBarFingerprint = fingerprint { internal val chipCloudFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
returns("V") returns("V")
parameters("Landroid/content/Context;", "L", "L", "L")
opcodes( opcodes(
Opcode.IPUT_OBJECT,
Opcode.CONST, Opcode.CONST,
Opcode.INVOKE_VIRTUAL, Opcode.CONST_4,
Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_STATIC,
Opcode.IPUT_OBJECT, Opcode.MOVE_RESULT_OBJECT
Opcode.CONST,
Opcode.INVOKE_VIRTUAL
) )
literal { chipCloud }
} }

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.music.layout.compactheader package app.revanced.patches.music.layout.compactheader
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
@@ -8,10 +8,14 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.PreferenceScreen import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.util.findFreeRegister
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
internal var chipCloud = -1L
private set
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
@Suppress("unused") @Suppress("unused")
@@ -33,28 +37,21 @@ val hideCategoryBar = bytecodePatch(
) )
execute { execute {
chipCloud = resourceMappings["layout", "chip_cloud"]
addResources("music", "layout.compactheader.hideCategoryBar") addResources("music", "layout.compactheader.hideCategoryBar")
PreferenceScreen.GENERAL.addPreferences( PreferenceScreen.GENERAL.addPreferences(
SwitchPreference("revanced_music_hide_category_bar"), SwitchPreference("revanced_music_hide_category_bar"),
) )
constructCategoryBarFingerprint.method.apply { chipCloudFingerprint.method.apply {
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex val targetIndex = chipCloudFingerprint.patternMatch!!.endIndex
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
val freeRegister = findFreeRegister(insertIndex, register)
addInstructionsWithLabels( addInstruction(
insertIndex, targetIndex + 1,
""" "invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar(Landroid/view/View;)V"
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar()Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
const/16 v$freeRegister, 0x8
invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V
:show
nop
"""
) )
} }
} }

View File

@@ -6,6 +6,7 @@ import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
import app.revanced.patches.music.misc.settings.PreferenceScreen import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_7_16_or_greater
import app.revanced.patches.music.playservice.is_7_33_or_greater import app.revanced.patches.music.playservice.is_7_33_or_greater
import app.revanced.patches.music.playservice.is_8_11_or_greater import app.revanced.patches.music.playservice.is_8_11_or_greater
import app.revanced.patches.music.playservice.is_8_15_or_greater import app.revanced.patches.music.playservice.is_8_15_or_greater
@@ -18,7 +19,7 @@ import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
val spoofVideoStreamsPatch = spoofVideoStreamsPatch( val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;", extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint, mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
fixMediaFetchHotConfig = { true }, fixMediaFetchHotConfig = { is_7_16_or_greater },
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater }, fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater }, fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },

View File

@@ -3,14 +3,11 @@ package app.revanced.patches.music.misc.tracks
import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.PreferenceScreen import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_8_10_or_greater import app.revanced.patches.music.playservice.is_8_05_or_greater
import app.revanced.patches.music.playservice.versionCheckPatch import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;"
@Suppress("unused") @Suppress("unused")
val forceOriginalAudioPatch = forceOriginalAudioPatch( val forceOriginalAudioPatch = forceOriginalAudioPatch(
block = { block = {
@@ -27,8 +24,8 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
) )
) )
}, },
fixUseLocalizedAudioTrackFlag = { is_8_10_or_greater }, fixUseLocalizedAudioTrackFlag = { is_8_05_or_greater },
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint, mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR, subclassExtensionClassDescriptor = "Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;",
preferenceScreen = PreferenceScreen.MISC, preferenceScreen = PreferenceScreen.MISC,
) )

View File

@@ -8,8 +8,12 @@ import kotlin.properties.Delegates
// Use notNull delegate so an exception is thrown if these fields are accessed before they are set. // Use notNull delegate so an exception is thrown if these fields are accessed before they are set.
var is_7_16_or_greater: Boolean by Delegates.notNull()
private set
var is_7_33_or_greater: Boolean by Delegates.notNull() var is_7_33_or_greater: Boolean by Delegates.notNull()
private set private set
var is_8_05_or_greater: Boolean by Delegates.notNull()
private set
var is_8_10_or_greater: Boolean by Delegates.notNull() var is_8_10_or_greater: Boolean by Delegates.notNull()
private set private set
var is_8_11_or_greater: Boolean by Delegates.notNull() var is_8_11_or_greater: Boolean by Delegates.notNull()
@@ -26,8 +30,10 @@ val versionCheckPatch = resourcePatch(
val playStoreServicesVersion = findPlayStoreServicesVersion() val playStoreServicesVersion = findPlayStoreServicesVersion()
// All bug fix releases always seem to use the same play store version as the minor version. // All bug fix releases always seem to use the same play store version as the minor version.
is_7_16_or_greater = 243499000 <= playStoreServicesVersion
is_7_33_or_greater = 245199000 <= playStoreServicesVersion is_7_33_or_greater = 245199000 <= playStoreServicesVersion
is_8_10_or_greater = 244799000 <= playStoreServicesVersion is_8_05_or_greater = 250599000 <= playStoreServicesVersion
is_8_10_or_greater = 251099000 <= playStoreServicesVersion
is_8_11_or_greater = 251199000 <= playStoreServicesVersion is_8_11_or_greater = 251199000 <= playStoreServicesVersion
is_8_15_or_greater = 251530000 <= playStoreServicesVersion is_8_15_or_greater = 251530000 <= playStoreServicesVersion
} }

View File

@@ -0,0 +1,34 @@
package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.asSequence
import org.w3c.dom.Element
@Suppress("unused")
internal val addManifestPermissionsPatch = resourcePatch {
val requiredPermissions = listOf(
"android.permission.READ_PHONE_STATE",
"android.permission.FOREGROUND_SERVICE_MICROPHONE",
"android.permission.RECORD_AUDIO",
)
execute {
document("AndroidManifest.xml").use { document ->
document.getElementsByTagName("manifest").item(0).let { manifestEl ->
// Check which permissions are missing
val existingPermissionNames = document.getElementsByTagName("uses-permission").asSequence()
.mapNotNull { (it as? Element)?.getAttribute("android:name") }.toSet()
val missingPermissions = requiredPermissions.filterNot { it in existingPermissionNames }
// Then add them
for (permission in missingPermissions) {
val element = document.createElement("uses-permission")
element.setAttribute("android:name", permission)
manifestEl.appendChild(element)
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
@file:Suppress("unused")
package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.fingerprint
import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.fromMethodReference
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val permissionRequestListFingerprint = fingerprint {
strings(
"android.permission.POST_NOTIFICATIONS",
"android.permission.READ_MEDIA_AUDIO",
"android.permission.RECORD_AUDIO"
)
custom { method, _ -> method.name == "<clinit>" }
}

View File

@@ -0,0 +1,42 @@
@file:Suppress("unused")
package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.samsung.radio.restrictions.device.bypassDeviceChecksPatch
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/samsung/radio/misc/fix/crash/FixCrashPatch;"
val fixCrashPatch = bytecodePatch(
name = "Fix crashes", description = "Prevents the app from crashing because of missing system permissions."
) {
dependsOn(addManifestPermissionsPatch, bypassDeviceChecksPatch)
extendWith("extensions/samsung/radio.rve")
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
execute {
permissionRequestListFingerprint.method.apply {
findInstructionIndicesReversedOrThrow(Opcode.FILLED_NEW_ARRAY).forEach { filledNewArrayIndex ->
val moveResultIndex = indexOfFirstInstruction(filledNewArrayIndex, Opcode.MOVE_RESULT_OBJECT)
if (moveResultIndex < 0) return@forEach // No move-result-object found after the filled-new-array
// Get the register where the array is saved
val arrayRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
// Invoke the method from the extension
addInstructions(
moveResultIndex + 1, """
invoke-static { v$arrayRegister }, ${EXTENSION_CLASS_DESCRIPTOR}->fixPermissionRequestList([Ljava/lang/String;)[Ljava/lang/String;
move-result-object v$arrayRegister
"""
)
}
}
}
}

View File

@@ -0,0 +1,55 @@
package app.revanced.patches.samsung.radio.restrictions.device
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.StringReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch;"
@Suppress("unused")
val bypassDeviceChecksPatch = bytecodePatch(
name = "Bypass device checks",
description = "Removes firmware and region blacklisting. " +
"This patch will still not allow the app to run on devices that do not have the required hardware.",
) {
extendWith("extensions/samsung/radio.rve")
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
execute {
// Return false = The device is not blacklisted
checkDeviceFingerprint.method.apply {
// Find the first string that start with "SM-", that's the list of incompatible devices
val firstStringIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string?.startsWith("SM-") == true
}
// Find the following filled-new-array (or filled-new-array/range) instruction
val filledNewArrayIndex = indexOfFirstInstructionOrThrow(firstStringIndex + 1) {
opcode == Opcode.FILLED_NEW_ARRAY || opcode == Opcode.FILLED_NEW_ARRAY_RANGE
}
// Find an available register for our use
val resultRegister = findFreeRegister(filledNewArrayIndex + 1)
// Store the array there and invoke the method that we added to the class earlier
addInstructions(
filledNewArrayIndex + 1, """
move-result-object v$resultRegister
invoke-static { v$resultRegister }, $EXTENSION_CLASS_DESCRIPTOR->checkIfDeviceIsIncompatible([Ljava/lang/String;)Z
move-result v$resultRegister
return v$resultRegister
"""
)
// Remove the instructions before our strings
removeInstructions(0, firstStringIndex)
}
}
}

View File

@@ -0,0 +1,61 @@
package app.revanced.patches.samsung.radio.restrictions.device
import app.revanced.patcher.fingerprint
import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.fromMethodReference
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val checkDeviceFingerprint = fingerprint {
returns("Z")
custom { method, _ ->
/* Check for methods call to:
- Landroid/os/SemSystemProperties;->getSalesCode()Ljava/lang/String;
- Landroid/os/SemSystemProperties;->getCountryIso()Ljava/lang/String;
*/
val impl = method.implementation ?: return@custom false
// Track which target methods we've found
val foundMethods = mutableSetOf<MethodCall>()
// Scan method instructions for calls to our target methods
for (instr in impl.instructions) {
val ref = instr.getReference<MethodReference>() ?: continue
val mc = fromMethodReference<MethodCall>(ref) ?: continue
if (mc == MethodCall.GetSalesCode || mc == MethodCall.GetCountryIso) {
foundMethods.add(mc)
// If we found both methods, return success
if (foundMethods.size == 2) {
return@custom true
}
}
}
// Only match if both methods are present
return@custom false
}
}
// Information about method calls we want to replace
private enum class MethodCall(
override val definedClassName: String,
override val methodName: String,
override val methodParams: Array<String>,
override val returnType: String,
) : IMethodCall {
GetSalesCode(
"Landroid/os/SemSystemProperties;",
"getSalesCode",
arrayOf(),
"Ljava/lang/String;",
),
GetCountryIso(
"Landroid/os/SemSystemProperties;",
"getCountryIso",
arrayOf(),
"Ljava/lang/String;",
),
}

View File

@@ -0,0 +1,25 @@
package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.patch.rawResourcePatch
import app.revanced.util.inputStreamFromBundledResource
import java.nio.file.Files
/**
* Copies a branding license text file to the target apk.
*
* This patch must be a dependency for all patches that add ReVanced branding to the target app.
*/
internal val addBrandLicensePatch = rawResourcePatch {
execute {
val brandingLicenseFileName = "LICENSE_REVANCED.TXT"
val inputFileStream = inputStreamFromBundledResource(
"branding-license",
brandingLicenseFileName
)!!
val targetFile = get(brandingLicenseFileName, false).toPath()
Files.copy(inputFileStream, targetFile)
}
}

View File

@@ -36,13 +36,13 @@ import org.w3c.dom.NodeList
import java.io.File import java.io.File
import java.util.logging.Logger import java.util.logging.Logger
private val mipmapDirectories = arrayOf( private val mipmapDirectories = mapOf(
// Target app does not have ldpi icons. // Target app does not have ldpi icons.
"mipmap-mdpi", "mipmap-mdpi" to "108x108 px",
"mipmap-hdpi", "mipmap-hdpi" to "162x162 px",
"mipmap-xhdpi", "mipmap-xhdpi" to "216x216 px",
"mipmap-xxhdpi", "mipmap-xxhdpi" to "324x324 px",
"mipmap-xxxhdpi" "mipmap-xxxhdpi" to "432x432 px"
) )
private val iconStyleNames = arrayOf( private val iconStyleNames = arrayOf(
@@ -104,10 +104,13 @@ internal fun baseCustomBrandingPatch(
Folder with images to use as a custom icon. Folder with images to use as a custom icon.
The folder must contain one or more of the following folders, depending on the DPI of the device: The folder must contain one or more of the following folders, depending on the DPI of the device:
${mipmapDirectories.joinToString("\n") { "- $it" }} ${mipmapDirectories.keys.joinToString("\n") { "- $it" }}
Each of the folders must contain all of the following files: Each of the folders must contain all of the following files:
${USER_CUSTOM_ADAPTIVE_FILE_NAMES.joinToString("\n")} ${USER_CUSTOM_ADAPTIVE_FILE_NAMES.joinToString("\n")}
The image dimensions must be as follows:
${mipmapDirectories.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
Optionally, the path contains a 'drawable' folder with any of the monochrome icon files: Optionally, the path contains a 'drawable' folder with any of the monochrome icon files:
$USER_CUSTOM_MONOCHROME_FILE_NAME $USER_CUSTOM_MONOCHROME_FILE_NAME
@@ -120,6 +123,7 @@ internal fun baseCustomBrandingPatch(
dependsOn( dependsOn(
addResourcesPatch, addResourcesPatch,
resourceMappingPatch, resourceMappingPatch,
addBrandLicensePatch,
bytecodePatch { bytecodePatch {
execute { execute {
mainActivityOnCreateFingerprint.method.addInstruction( mainActivityOnCreateFingerprint.method.addInstruction(
@@ -249,7 +253,7 @@ internal fun baseCustomBrandingPatch(
) )
// Copy template icon files. // Copy template icon files.
mipmapDirectories.forEach { dpi -> mipmapDirectories.keys.forEach { dpi ->
copyResources( copyResources(
"custom-branding", "custom-branding",
ResourceGroup( ResourceGroup(
@@ -405,23 +409,24 @@ internal fun baseCustomBrandingPatch(
) )
} }
val sourceFolders = iconPathFile.listFiles { file -> file.isDirectory }
?: throw PatchException("The custom icon path contains no subfolders: " +
iconPathFile.absolutePath)
val resourceDirectory = get("res") val resourceDirectory = get("res")
var copiedFiles = false var copiedFiles = false
// For each source folder, copy the files to the target resource directories. // For each source folder, copy the files to the target resource directories.
sourceFolders.forEach { dpiSourceFolder -> iconPathFile.listFiles {
file -> file.isDirectory && file.name in mipmapDirectories
}!!.forEach { dpiSourceFolder ->
val targetDpiFolder = resourceDirectory.resolve(dpiSourceFolder.name) val targetDpiFolder = resourceDirectory.resolve(dpiSourceFolder.name)
if (!targetDpiFolder.exists()) return@forEach if (!targetDpiFolder.exists()) {
// Should never happen.
throw IllegalStateException("Resource not found: $dpiSourceFolder")
}
val customFiles = dpiSourceFolder.listFiles { file -> val customFiles = dpiSourceFolder.listFiles { file ->
file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES
}!! }!!
if (customFiles.size > 0 && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) { if (customFiles.isNotEmpty() && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
throw PatchException("Must include all required icon files " + throw PatchException("Must include all required icon files " +
"but only found " + customFiles.map { it.name }) "but only found " + customFiles.map { it.name })
} }
@@ -451,8 +456,9 @@ internal fun baseCustomBrandingPatch(
} }
if (!copiedFiles) { if (!copiedFiles) {
throw PatchException("Could not find any replacement images in " + throw PatchException("Expected to find directories and files: "
"patch option path: " + iconPathFile.absolutePath) + USER_CUSTOM_ADAPTIVE_FILE_NAMES.contentToString()
+ "\nBut none were found in the provided option file path: " + iconPathFile.absolutePath)
} }
} }

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.shared.misc.audio package app.revanced.patches.shared.misc.audio
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal val formatStreamModelToStringFingerprint = fingerprint { internal val formatStreamModelToStringFingerprint = fingerprint {
@@ -20,10 +20,7 @@ internal val formatStreamModelToStringFingerprint = fingerprint {
internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L
internal val selectAudioStreamFingerprint = fingerprint { internal val selectAudioStreamFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) literal {
returns("L") AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG
custom { method, _ ->
method.parameters.size > 2 // Method has a large number of parameters and may change.
&& method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG)
} }
} }

View File

@@ -34,7 +34,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
internal fun forceOriginalAudioPatch( internal fun forceOriginalAudioPatch(
block: BytecodePatchBuilder.() -> Unit = {}, block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {}, executeBlock: BytecodePatchContext.() -> Unit = {},
fixUseLocalizedAudioTrackFlag: () -> Boolean, fixUseLocalizedAudioTrackFlag: BytecodePatchContext.() -> Boolean,
mainActivityOnCreateFingerprint: Fingerprint, mainActivityOnCreateFingerprint: Fingerprint,
subclassExtensionClassDescriptor: String, subclassExtensionClassDescriptor: String,
preferenceScreen: BasePreferenceScreen.Screen preferenceScreen: BasePreferenceScreen.Screen

View File

@@ -6,6 +6,7 @@ import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResource import app.revanced.patches.all.misc.resources.addResource
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.layout.branding.addBrandLicensePatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
@@ -61,7 +62,11 @@ fun settingsPatch (
rootPreferences: List<Pair<BasePreference, String>>? = null, rootPreferences: List<Pair<BasePreference, String>>? = null,
preferences: Set<BasePreference>, preferences: Set<BasePreference>,
) = resourcePatch { ) = resourcePatch {
dependsOn(addResourcesPatch, settingsColorPatch) dependsOn(
addResourcesPatch,
settingsColorPatch,
addBrandLicensePatch
)
execute { execute {
copyResources( copyResources(

View File

@@ -47,11 +47,15 @@ val changeLyricsProviderPatch = bytecodePatch(
// may not allow network connections or the network may be down. // may not allow network connections or the network may be down.
try { try {
InetAddress.getByName(host) InetAddress.getByName(host)
} catch (e: UnknownHostException) { } catch (_: UnknownHostException) {
Logger.getLogger(this::class.java.name).warning( Logger.getLogger(this::class.java.name).warning(
"Host \"$host\" did not resolve to any domain." "Host \"$host\" did not resolve to any domain."
) )
} catch (_: Exception) {
// Must ignore any kind of exception. Trying to resolve network
// on Manager throws android.os.NetworkOnMainThreadException
} }
true true
} }

View File

@@ -3,14 +3,20 @@ package app.revanced.patches.tiktok.interaction.downloads
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.settingsPatch import app.revanced.patches.tiktok.misc.settings.settingsPatch
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/download/DownloadsPatch;"
@Suppress("unused") @Suppress("unused")
val downloadsPatch = bytecodePatch( val downloadsPatch = bytecodePatch(
@@ -28,60 +34,45 @@ val downloadsPatch = bytecodePatch(
) )
execute { execute {
aclCommonShareFingerprint.method.replaceInstructions( aclCommonShareFingerprint.method.returnEarly(0)
0, aclCommonShare2Fingerprint.method.returnEarly(2)
"""
const/4 v0, 0x0
return v0
""",
)
aclCommonShare2Fingerprint.method.replaceInstructions(
0,
"""
const/4 v0, 0x2
return v0
""",
)
// Download videos without watermark. // Download videos without watermark.
aclCommonShare3Fingerprint.method.addInstructionsWithLabels( aclCommonShare3Fingerprint.method.addInstructionsWithLabels(
0, 0,
""" """
invoke-static {}, Lapp/revanced/extension/tiktok/download/DownloadsPatch;->shouldRemoveWatermark()Z invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldRemoveWatermark()Z
move-result v0 move-result v0
if-eqz v0, :noremovewatermark if-eqz v0, :noremovewatermark
const/4 v0, 0x1 const/4 v0, 0x1
return v0 return v0
:noremovewatermark :noremovewatermark
nop nop
""", """,
) )
// Change the download path patch. // Change the download path patch.
downloadUriFingerprint.method.apply { downloadUriFingerprint.method.apply {
val firstIndex = indexOfFirstInstructionOrThrow { findInstructionIndicesReversedOrThrow {
getReference<MethodReference>()?.name == "<init>" getReference<FieldReference>().let {
} it?.definingClass == "Landroid/os/Environment;" && it.name.startsWith("DIRECTORY_")
val secondIndex = indexOfFirstInstructionOrThrow { }
getReference<MethodReference>()?.returnType?.contains("Uri") == true }.forEach { fieldIndex ->
} val pathRegister = getInstruction<OneRegisterInstruction>(fieldIndex).registerA
val builderRegister = getInstruction<FiveRegisterInstruction>(fieldIndex + 1).registerC
addInstructions( // Remove 'field load → append → "/Camera/" → append' block.
secondIndex, removeInstructions(fieldIndex, 4)
"""
invoke-static {}, Lapp/revanced/extension/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String;
move-result-object v0
""",
)
addInstructions( addInstructions(
firstIndex, fieldIndex,
""" """
invoke-static {}, Lapp/revanced/extension/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String; invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->getDownloadPath()Ljava/lang/String;
move-result-object v0 move-result-object v$pathRegister
""", invoke-virtual { v$builderRegister, v$pathRegister }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
) """,
)
}
} }
settingsStatusLoadFingerprint.method.addInstruction( settingsStatusLoadFingerprint.method.addInstruction(

View File

@@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.layout.branding.addBrandLicensePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
@@ -18,7 +19,7 @@ val settingsPatch = bytecodePatch(
name = "Settings", name = "Settings",
description = "Adds ReVanced settings to TikTok.", description = "Adds ReVanced settings to TikTok.",
) { ) {
dependsOn(sharedExtensionPatch) dependsOn(sharedExtensionPatch, addBrandLicensePatch)
compatibleWith( compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"), "com.ss.android.ugc.trill"("36.5.4"),

View File

@@ -0,0 +1,25 @@
package app.revanced.patches.tiktok.misc.share
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val urlShorteningFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL)
returns("LX/")
parameters(
"I",
"Ljava/lang/String;",
"Ljava/lang/String;",
"Ljava/lang/String;"
)
opcodes(Opcode.RETURN_OBJECT)
// Same Kotlin intrinsics literal on both variants.
strings("getShortShareUrlObservab\u2026ongUrl, subBizSceneValue)")
custom { method, _ ->
// LIZLLL is obfuscated by ProGuard/R8, but stable across both TikTok and Musically.
method.name == "LIZLLL"
}
}

View File

@@ -0,0 +1,85 @@
package app.revanced.patches.tiktok.misc.share
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.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tiktok/share/ShareUrlSanitizer;"
@Suppress("unused")
val sanitizeShareUrlsPatch = bytecodePatch(
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
) {
dependsOn(sharedExtensionPatch)
compatibleWith(
"com.ss.android.ugc.trill"("36.5.4"),
"com.zhiliaoapp.musically"("36.5.4"),
)
execute {
urlShorteningFingerprint.method.apply {
val invokeIndex = indexOfFirstInstructionOrThrow {
val ref = getReference<MethodReference>()
ref?.name == "LIZ" && ref.definingClass.startsWith("LX/")
}
val moveResultIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.MOVE_RESULT_OBJECT)
val urlRegister = getInstruction<OneRegisterInstruction>(moveResultIndex).registerA
// Resolve Observable wrapper classes at runtime
val observableWrapperIndex = indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE)
val observableWrapperClass = getInstruction<ReferenceInstruction>(observableWrapperIndex)
.reference.toString()
val observableFactoryIndex = indexOfFirstInstructionOrThrow {
val ref = getReference<MethodReference>()
ref?.name == "LJ" && ref.definingClass.startsWith("LX/")
}
val observableFactoryRef = getInstruction<ReferenceInstruction>(observableFactoryIndex)
.reference as MethodReference
val observableFactoryClass = observableFactoryRef.definingClass
val observableInterfaceType = observableFactoryRef.parameterTypes.first()
val observableReturnType = observableFactoryRef.returnType
val wrapperRegister = findFreeRegister(moveResultIndex + 1, urlRegister)
// Check setting and conditionally sanitize share URL.
addInstructionsWithLabels(
moveResultIndex + 1,
"""
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldSanitize()Z
move-result v$wrapperRegister
if-eqz v$wrapperRegister, :skip_sanitization
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$urlRegister
# Wrap sanitized URL and return early to bypass ShareExtService
new-instance v$wrapperRegister, $observableWrapperClass
invoke-direct { v$wrapperRegister, v$urlRegister }, $observableWrapperClass-><init>(Ljava/lang/String;)V
invoke-static { v$wrapperRegister }, $observableFactoryClass->LJ($observableInterfaceType)$observableReturnType
move-result-object v$urlRegister
return-object v$urlRegister
:skip_sanitization
nop
"""
)
}
}
}

View File

@@ -1,23 +1,26 @@
package app.revanced.patches.twitter.misc.links package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption import app.revanced.patcher.patch.stringOption
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN 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.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
import app.revanced.util.findElementByAttributeValueOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import java.net.InetAddress import java.net.InetAddress
import java.net.UnknownHostException import java.net.UnknownHostException
import java.util.logging.Logger import java.util.logging.Logger
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;" internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;"
internal val domainNameOption by stringOption( internal val domainNameOption = stringOption(
key = "domainName", key = "domainName",
default = "https://fxtwitter.com", default = "fxtwitter.com",
title = "Domain name", title = "Domain name",
description = "The domain name to use when sharing links.", description = "The domain name to use when sharing links.",
required = true, required = true,
@@ -28,23 +31,25 @@ internal val domainNameOption by stringOption(
// may not allow network connections or the network may be down. // may not allow network connections or the network may be down.
try { try {
InetAddress.getByName(it) InetAddress.getByName(it)
} catch (e: UnknownHostException) { } catch (_: UnknownHostException) {
Logger.getLogger(this::class.java.name).warning( Logger.getLogger(this::class.java.name).warning(
"Host \"$it\" did not resolve to any domain." "Host \"$it\" did not resolve to any domain."
) )
} catch (_: Exception) {
// Must ignore any kind of exception. Trying to resolve network
// on Manager throws android.os.NetworkOnMainThreadException
} }
true true
} }
// TODO restore this once Manager uses a fixed version of Patcher
/*
internal val changeLinkSharingDomainResourcePatch = resourcePatch { internal val changeLinkSharingDomainResourcePatch = resourcePatch {
execute { execute {
val domainName = domainNameOption!! val domainName = domainNameOption.value!!
val shareLinkTemplate = if (domainName.endsWith("/")) { val shareLinkTemplate = "https://$domainName/%1\$s/status/%2\$s"
"$domainName%1\$s/status/%2\$s"
} else {
"$domainName/%1\$s/status/%2\$s"
}
document("res/values/strings.xml").use { document -> document("res/values/strings.xml").use { document ->
document.documentElement.childNodes.findElementByAttributeValueOrThrow( document.documentElement.childNodes.findElementByAttributeValueOrThrow(
@@ -54,14 +59,15 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch {
} }
} }
} }
*/
@Suppress("unused") @Suppress("unused")
val changeLinkSharingDomainPatch = bytecodePatch( val changeLinkSharingDomainPatch = bytecodePatch(
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN, name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN description = "$PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN Including this patch can prevent making posts that quote other posts.",
use = false
) { ) {
dependsOn( dependsOn(
changeLinkSharingDomainResourcePatch,
sharedExtensionPatch, sharedExtensionPatch,
) )
@@ -72,11 +78,11 @@ val changeLinkSharingDomainPatch = bytecodePatch(
) )
) )
execute { val domainName by domainNameOption()
val domainName = domainNameOption!!
execute {
// Replace the domain name in the link sharing extension methods. // Replace the domain name in the link sharing extension methods.
linkSharingDomainHelperFingerprint.method.returnEarly(domainName) linkSharingDomainHelperFingerprint.method.returnEarly(domainName!!)
// Replace the domain name when copying a link with "Copy link" button. // Replace the domain name when copying a link with "Copy link" button.
linkBuilderFingerprint.method.addInstructions( linkBuilderFingerprint.method.addInstructions(
@@ -87,5 +93,22 @@ val changeLinkSharingDomainPatch = bytecodePatch(
return-object p0 return-object p0
""" """
) )
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
// Replace the domain name in the "Share via..." dialog.
linkResourceGetterFingerprint.method.apply {
val templateIdConstIndex = indexOfFirstInstructionOrThrow(Opcode.CONST)
// 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;",
)
}
} }
} }

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.twitter.misc.links package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal val openLinkFingerprint = fingerprint { internal val openLinkFingerprint = fingerprint {
returns("V") returns("V")
@@ -17,6 +18,18 @@ internal val linkBuilderFingerprint = fingerprint {
strings("/%1\$s/status/%2\$d") strings("/%1\$s/status/%2\$d")
} }
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
// Returns a shareable link for the "Share via..." dialog.
internal val linkResourceGetterFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Landroid/content/res/Resources;")
custom { _, classDef ->
classDef.fields.any { field ->
field.type.startsWith("Lcom/twitter/model/core/")
}
}
}
internal val linkSharingDomainHelperFingerprint = fingerprint { internal val linkSharingDomainHelperFingerprint = fingerprint {
custom { method, classDef -> custom { method, classDef ->
method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR

View File

@@ -9,6 +9,7 @@ import app.revanced.patcher.patch.stringOption
import app.revanced.patcher.util.Document import app.revanced.patcher.util.Document
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.layout.branding.addBrandLicensePatch
import app.revanced.patches.shared.misc.mapping.get import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.mapping.resourceMappings
@@ -24,15 +25,43 @@ import java.io.File
private val variants = arrayOf("light", "dark") private val variants = arrayOf("light", "dark")
private const val EXTENSION_CLASS_DESCRIPTOR = private val targetResourceDirectoryNames = mapOf(
"Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;" "drawable-hdpi" to "194x72 px",
"drawable-xhdpi" to "258x96 px",
"drawable-xxhdpi" to "387x144 px",
"drawable-xxxhdpi" to "512x192 px"
)
/**
* Header logos built into this patch.
*/
private val logoResourceNames = arrayOf(
"revanced_header_minimal",
"revanced_header_rounded",
)
/**
* Custom header resource/file name.
*/
private const val CUSTOM_HEADER_RESOURCE_NAME = "revanced_header_custom"
/**
* Custom header resource/file names.
*/
private val customHeaderResourceFileNames = variants.map { variant ->
"${CUSTOM_HEADER_RESOURCE_NAME}_$variant.png"
}.toTypedArray()
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;"
private val changeHeaderBytecodePatch = bytecodePatch { private val changeHeaderBytecodePatch = bytecodePatch {
dependsOn(resourceMappingPatch) dependsOn(
resourceMappingPatch,
addBrandLicensePatch
)
execute { execute {
// Resources are not used during patching, but extension code uses these // Verify images exist. Resources are not used during patching but extension code does.
// images so verify they exist.
arrayOf( arrayOf(
"yt_ringo2_wordmark_header", "yt_ringo2_wordmark_header",
"yt_ringo2_premium_wordmark_header" "yt_ringo2_premium_wordmark_header"
@@ -62,28 +91,6 @@ private val changeHeaderBytecodePatch = bytecodePatch {
} }
} }
private val targetResourceDirectoryNames = mapOf(
"xxxhdpi" to "512px x 192px",
"xxhdpi" to "387px x 144px",
"xhdpi" to "258px x 96px",
"hdpi" to "194px x 72px",
"mdpi" to "129px x 48px"
).mapKeys { (dpi, _) -> "drawable-$dpi" }
/**
* Header logos built into this patch.
*/
private val logoResourceNames = arrayOf(
"revanced_header_logo_minimal",
"revanced_header_logo",
)
/**
* Custom header resource/file name.
*/
private const val CUSTOM_HEADER_RESOURCE_NAME = "custom_header"
@Suppress("unused") @Suppress("unused")
val changeHeaderPatch = resourcePatch( val changeHeaderPatch = resourcePatch(
name = "Change header", name = "Change header",
@@ -110,7 +117,7 @@ val changeHeaderPatch = resourcePatch(
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }} ${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
Each of the folders must contain all of the following files: Each of the folders must contain all of the following files:
${variants.joinToString("\n") { variant -> "- ${CUSTOM_HEADER_RESOURCE_NAME}_$variant.png" }} ${customHeaderResourceFileNames.joinToString("\n")}
The image dimensions must be as follows: The image dimensions must be as follows:
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")} ${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
@@ -120,67 +127,41 @@ val changeHeaderPatch = resourcePatch(
execute { execute {
addResources("youtube", "layout.branding.changeHeaderPatch") addResources("youtube", "layout.branding.changeHeaderPatch")
fun getLightDarkFileNames(vararg resourceNames: String): Array<String> = PreferenceScreen.GENERAL_LAYOUT.addPreferences(
variants.flatMap { variant -> if (custom == null) {
resourceNames.map { resource -> "${resource}_$variant.png" } ListPreference("revanced_header_logo")
}.toTypedArray() } else {
ListPreference(
val logoResourceFileNames = getLightDarkFileNames(*logoResourceNames) key = "revanced_header_logo",
copyResources( entriesKey = "revanced_header_logo_custom_entries",
"change-header", entryValuesKey = "revanced_header_logo_custom_entry_values"
ResourceGroup("drawable-hdpi", *logoResourceFileNames),
ResourceGroup("drawable-mdpi", *logoResourceFileNames),
ResourceGroup("drawable-xhdpi", *logoResourceFileNames),
ResourceGroup("drawable-xxhdpi", *logoResourceFileNames),
ResourceGroup("drawable-xxxhdpi", *logoResourceFileNames),
)
if (custom != null) {
val customFile = File(custom!!)
if (!customFile.exists()) {
throw PatchException("The custom icon path cannot be found: " +
customFile.absolutePath
) )
} }
)
if (!customFile.isDirectory) { logoResourceNames.forEach { logo ->
throw PatchException("The custom icon path must be a folder: " variants.forEach { variant ->
+ customFile.absolutePath) copyResources(
"change-header",
ResourceGroup(
"drawable",
logo + "_" + variant + ".xml"
)
)
} }
}
val sourceFolders = customFile.listFiles { file -> file.isDirectory } // Copy custom template. Images are only used if settings
?: throw PatchException("The custom icon path contains no subfolders: " + // are imported and a custom header is enabled.
customFile.absolutePath) targetResourceDirectoryNames.keys.forEach { dpi ->
variants.forEach { variant ->
val customResourceFileNames = getLightDarkFileNames(CUSTOM_HEADER_RESOURCE_NAME) copyResources(
"change-header",
var copiedFiles = false ResourceGroup(
dpi,
// For each source folder, copy the files to the target resource directories. *customHeaderResourceFileNames
sourceFolders.forEach { dpiSourceFolder -> )
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name) )
if (!targetDpiFolder.exists()) return@forEach
val customFiles = dpiSourceFolder.listFiles { file ->
file.isFile && file.name in customResourceFileNames
}!!
if (customFiles.size > 0 && customFiles.size != variants.size) {
throw PatchException("Both light/dark mode images " +
"must be specified but only found: " + customFiles.map { it.name })
}
customFiles.forEach { imgSourceFile ->
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
imgSourceFile.copyTo(imgTargetFile)
copiedFiles = true
}
}
if (!copiedFiles) {
throw PatchException("No custom header images found in " +
"the provided path: " + customFile.absolutePath)
} }
} }
@@ -199,9 +180,7 @@ val changeHeaderPatch = resourcePatch(
addAttributeReference(logoName) addAttributeReference(logoName)
} }
if (custom != null) { addAttributeReference(CUSTOM_HEADER_RESOURCE_NAME)
addAttributeReference(CUSTOM_HEADER_RESOURCE_NAME)
}
} }
// Add custom drawables to all styles that use the regular and premium logo. // Add custom drawables to all styles that use the regular and premium logo.
@@ -227,22 +206,58 @@ val changeHeaderPatch = resourcePatch(
addDrawableElement(document, logoName, mode) addDrawableElement(document, logoName, mode)
} }
if (custom != null) { addDrawableElement(document, CUSTOM_HEADER_RESOURCE_NAME, mode)
addDrawableElement(document, CUSTOM_HEADER_RESOURCE_NAME, mode)
}
} }
} }
PreferenceScreen.GENERAL_LAYOUT.addPreferences( // Copy user provided images last, so if an exception is thrown due to bad input.
if (custom == null) { if (custom != null) {
ListPreference("revanced_header_logo") val customFile = File(custom!!.trim())
} else { if (!customFile.exists()) {
ListPreference( throw PatchException("The custom header path cannot be found: " +
key = "revanced_header_logo", customFile.absolutePath
entriesKey = "revanced_header_logo_custom_entries",
entryValuesKey = "revanced_header_logo_custom_entry_values"
) )
} }
)
if (!customFile.isDirectory) {
throw PatchException("The custom header path must be a folder: "
+ customFile.absolutePath)
}
var copiedFiles = false
// For each source folder, copy the files to the target resource directories.
customFile.listFiles {
file -> file.isDirectory && file.name in targetResourceDirectoryNames
}!!.forEach { dpiSourceFolder ->
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name)
if (!targetDpiFolder.exists()) {
// Should never happen.
throw IllegalStateException("Resource not found: $dpiSourceFolder")
}
val customFiles = dpiSourceFolder.listFiles { file ->
file.isFile && file.name in customHeaderResourceFileNames
}!!
if (customFiles.isNotEmpty() && customFiles.size != variants.size) {
throw PatchException("Both light/dark mode images " +
"must be specified but only found: " + customFiles.map { it.name })
}
customFiles.forEach { imgSourceFile ->
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
imgSourceFile.copyTo(target = imgTargetFile, overwrite = true)
copiedFiles = true
}
}
if (!copiedFiles) {
throw PatchException("Expected to find directories and files: "
+ customHeaderResourceFileNames.contentToString()
+ "\nBut none were found in the provided option file path: " + customFile.absolutePath)
}
}
} }
} }

View File

@@ -147,6 +147,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
SwitchPreference("revanced_hide_chapters_section"), SwitchPreference("revanced_hide_chapters_section"),
SwitchPreference("revanced_hide_info_cards_section"), SwitchPreference("revanced_hide_info_cards_section"),
SwitchPreference("revanced_hide_how_this_was_made_section"), SwitchPreference("revanced_hide_how_this_was_made_section"),
SwitchPreference("revanced_hide_hype_points"),
SwitchPreference("revanced_hide_key_concepts_section"), SwitchPreference("revanced_hide_key_concepts_section"),
SwitchPreference("revanced_hide_podcast_section"), SwitchPreference("revanced_hide_podcast_section"),
SwitchPreference("revanced_hide_transcript_section"), SwitchPreference("revanced_hide_transcript_section"),

View File

@@ -45,10 +45,10 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
SwitchPreference("revanced_hide_player_flyout_loop_video"), SwitchPreference("revanced_hide_player_flyout_loop_video"),
SwitchPreference("revanced_hide_player_flyout_ambient_mode"), SwitchPreference("revanced_hide_player_flyout_ambient_mode"),
SwitchPreference("revanced_hide_player_flyout_stable_volume"), SwitchPreference("revanced_hide_player_flyout_stable_volume"),
SwitchPreference("revanced_hide_player_flyout_listen_with_youtube_music"),
SwitchPreference("revanced_hide_player_flyout_help"), SwitchPreference("revanced_hide_player_flyout_help"),
SwitchPreference("revanced_hide_player_flyout_speed"), SwitchPreference("revanced_hide_player_flyout_speed"),
SwitchPreference("revanced_hide_player_flyout_lock_screen"), SwitchPreference("revanced_hide_player_flyout_lock_screen"),
SwitchPreference("revanced_hide_player_flyout_more_info"),
SwitchPreference( SwitchPreference(
key = "revanced_hide_player_flyout_audio_track", key = "revanced_hide_player_flyout_audio_track",
tag = "app.revanced.extension.youtube.settings.preference.HideAudioFlyoutMenuPreference" tag = "app.revanced.extension.youtube.settings.preference.HideAudioFlyoutMenuPreference"

View File

@@ -1,11 +1,9 @@
package app.revanced.patches.youtube.layout.seekbar package app.revanced.patches.youtube.layout.seekbar
import app.revanced.patcher.Fingerprint 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.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
@@ -17,17 +15,13 @@ import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.inputStreamFromBundledResource
import app.revanced.util.insertLiteralOverride import app.revanced.util.insertLiteralOverride
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@@ -38,9 +32,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import org.w3c.dom.Element
import java.io.ByteArrayInputStream
import kotlin.use
internal var reelTimeBarPlayedColorId = -1L internal var reelTimeBarPlayedColorId = -1L
private set private set
@@ -57,8 +48,6 @@ internal var ytTextSecondaryId = -1L
internal var inlineTimeBarLiveSeekableRangeId = -1L internal var inlineTimeBarLiveSeekableRangeId = -1L
private set private set
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
private val seekbarColorResourcePatch = resourcePatch { private val seekbarColorResourcePatch = resourcePatch {
dependsOn( dependsOn(
settingsPatch, settingsPatch,
@@ -92,21 +81,6 @@ private val seekbarColorResourcePatch = resourcePatch {
"inline_time_bar_live_seekable_range" "inline_time_bar_live_seekable_range"
] ]
// Modify the resume playback drawable and replace the progress bar with a custom drawable.
document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
val layerList = document.getElementsByTagName("layer-list").item(0) as Element
val progressNode = layerList.getElementsByTagName("item").item(1) as Element
if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {
throw PatchException("Could not find progress bar")
}
val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element
val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element
val replacementNode = document.createElement(
"app.revanced.extension.youtube.patches.theme.ProgressBarDrawable",
)
scaleNode.replaceChild(replacementNode, shapeNode)
}
ytYoutubeMagentaColorId = resourceMappings[ ytYoutubeMagentaColorId = resourceMappings[
"color", "color",
"yt_youtube_magenta", "yt_youtube_magenta",
@@ -115,99 +89,9 @@ private val seekbarColorResourcePatch = resourcePatch {
"attr", "attr",
"ytStaticBrandRed", "ytStaticBrandRed",
] ]
// Add attribute and styles for splash screen custom color.
// Using a style is the only way to selectively change just the seekbar fill color.
//
// Because the style colors must be hard coded for all color possibilities,
// instead of allowing 24 bit color the style is restricted to 9-bit (3 bits per color channel)
// and the style color closest to the users custom color is used for the splash screen.
arrayOf(
inputStreamFromBundledResource("seekbar/values", "attrs.xml")!! to "res/values/attrs.xml",
ByteArrayInputStream(create9BitSeekbarColorStyles().toByteArray()) to "res/values/styles.xml"
).forEach { (source, destination) ->
"resources".copyXmlNode(
document(source),
document(destination),
).close()
}
fun setSplashDrawablePathFillColor(xmlFileNames: Iterable<String>, vararg resourceNames: String) {
xmlFileNames.forEach { xmlFileName ->
document(xmlFileName).use { document ->
val childNodes = document.childNodes
resourceNames.forEach { elementId ->
val element = childNodes.findElementByAttributeValueOrThrow(
"android:name",
elementId
)
val attribute = "android:fillColor"
if (!element.hasAttribute(attribute)) {
throw PatchException("Could not find $attribute for $elementId")
}
element.setAttribute(attribute, "?attr/$splashSeekbarColorAttributeName")
}
}
}
}
setSplashDrawablePathFillColor(
listOf(
"res/drawable/\$startup_animation_light__0.xml",
"res/drawable/\$startup_animation_dark__0.xml"
),
"_R_G_L_10_G_D_0_P_0"
)
if (!is_19_46_or_greater) {
// Resources removed in 19.46+
setSplashDrawablePathFillColor(
listOf(
"res/drawable/\$buenos_aires_animation_light__0.xml",
"res/drawable/\$buenos_aires_animation_dark__0.xml"
),
"_R_G_L_8_G_D_0_P_0"
)
}
} }
} }
/**
* Generate a style xml with all combinations of 9-bit colors.
*/
private fun create9BitSeekbarColorStyles(): String = StringBuilder().apply {
append("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
append("<resources>\n")
for (red in 0..7) {
for (green in 0..7) {
for (blue in 0..7) {
val name = "${red}_${green}_${blue}"
fun roundTo3BitHex(channel8Bits: Int) =
(channel8Bits * 255 / 7).toString(16).padStart(2, '0')
val r = roundTo3BitHex(red)
val g = roundTo3BitHex(green)
val b = roundTo3BitHex(blue)
val color = "#ff$r$g$b"
append(
"""
<style name="splash_seekbar_color_style_$name">
<item name="$splashSeekbarColorAttributeName">$color</item>
</style>
"""
)
}
}
}
append("</resources>")
}.toString()
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;"
val seekbarColorPatch = bytecodePatch( val seekbarColorPatch = bytecodePatch(
@@ -344,21 +228,6 @@ val seekbarColorPatch = bytecodePatch(
// Hook the splash animation to set the a seekbar color. // Hook the splash animation to set the a seekbar color.
mainActivityOnCreateFingerprint.method.apply { mainActivityOnCreateFingerprint.method.apply {
val drawableIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/widget/ImageView;"
&& reference.name == "getDrawable"
}
val checkCastIndex = indexOfFirstInstructionOrThrow(drawableIndex, Opcode.CHECK_CAST)
val drawableRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$drawableRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setSplashAnimationDrawableTheme(Landroid/graphics/drawable/AnimatedVectorDrawable;)V"
)
// Replace the Lottie animation view setAnimation(int) call.
val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name val setAnimationIntMethodName = lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name
findInstructionIndicesReversedOrThrow { findInstructionIndicesReversedOrThrow {
@@ -371,13 +240,11 @@ val seekbarColorPatch = bytecodePatch(
replaceInstruction( replaceInstruction(
index, index,
"invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " + "invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " +
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" + "$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie(Lcom/airbnb/lottie/LottieAnimationView;I)V"
"(Lcom/airbnb/lottie/LottieAnimationView;I)V"
) )
} }
} }
// Add non obfuscated method aliases for `setAnimation(int)` // Add non obfuscated method aliases for `setAnimation(int)`
// and `setAnimation(InputStream, String)` so extension code can call them. // and `setAnimation(InputStream, String)` so extension code can call them.
lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply { lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply {

View File

@@ -63,13 +63,6 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference" tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
), ),
SwitchPreference("revanced_spoof_video_streams_av1"), SwitchPreference("revanced_spoof_video_streams_av1"),
ListPreference(
key = "revanced_spoof_video_streams_language",
// Language strings are declared in Setting patch.
entriesKey = "revanced_language_entries",
entryValuesKey = "revanced_language_entry_values",
tag = "app.revanced.extension.youtube.settings.preference.SpoofAudioSelectorListPreference"
),
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"), SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"),
) )
) )

View File

@@ -8,9 +8,6 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;"
@Suppress("unused") @Suppress("unused")
val forceOriginalAudioPatch = forceOriginalAudioPatch( val forceOriginalAudioPatch = forceOriginalAudioPatch(
block = { block = {
@@ -31,6 +28,6 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
}, },
fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater }, fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater },
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint, mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR, subclassExtensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;",
preferenceScreen = PreferenceScreen.VIDEO, preferenceScreen = PreferenceScreen.VIDEO,
) )

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1639,10 +1639,6 @@ Second \"item\" text"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">عرض في إحصاءات تقنية</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">عرض في إحصاءات تقنية</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">يتم عرض نوع العميل في إحصاءات تقنية</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">يتم عرض نوع العميل في إحصاءات تقنية</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">تم إخفاء نوع العميل في إحصاءات تقنية</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">تم إخفاء نوع العميل في إحصاءات تقنية</string>
<string name="revanced_spoof_video_streams_language_title">لغة بث الصوت</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">لتحديد لغة صوتية معينة، قم بإيقاف تشغيل \'فرض لغة الصوت الأصلية\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">اختيار لغة البث غير متاح مع Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -259,7 +259,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -218,9 +218,9 @@ Hər halda, bunu aktivləşdirmə IP ünvanınız kimi bəzi istifadəçi məlum
<string name="revanced_hide_community_posts_title">İcma elanların gizlət</string> <string name="revanced_hide_community_posts_title">İcma elanların gizlət</string>
<string name="revanced_hide_community_posts_summary_on">İcma elanları gizlədilib</string> <string name="revanced_hide_community_posts_summary_on">İcma elanları gizlədilib</string>
<string name="revanced_hide_community_posts_summary_off">İcma elanları göstərilir</string> <string name="revanced_hide_community_posts_summary_off">İcma elanları göstərilir</string>
<string name="revanced_hide_compact_banner_title">Yığcam etiketləri gizlət</string> <string name="revanced_hide_compact_banner_title">Yığcam afişaları gizlət</string>
<string name="revanced_hide_compact_banner_summary_on">Yığcam etiketlər gizlidir</string> <string name="revanced_hide_compact_banner_summary_on">Yığcam afişalar gizlidir</string>
<string name="revanced_hide_compact_banner_summary_off">Yığcam etiketlər göstərilir</string> <string name="revanced_hide_compact_banner_summary_off">Yığcam afişalar görünür</string>
<string name="revanced_hide_crowdfunding_box_title">İanə qutusunu gizlət</string> <string name="revanced_hide_crowdfunding_box_title">İanə qutusunu gizlət</string>
<string name="revanced_hide_crowdfunding_box_summary_on">İanə qutusu gizlidir</string> <string name="revanced_hide_crowdfunding_box_summary_on">İanə qutusu gizlidir</string>
<string name="revanced_hide_crowdfunding_box_summary_off">İanə qutusu göstərilir</string> <string name="revanced_hide_crowdfunding_box_summary_off">İanə qutusu göstərilir</string>
@@ -471,9 +471,9 @@ Məhdudiyyətlər
<string name="revanced_hide_creator_store_shelf_title">Yaradıcı mağaza bölümün gizlət</string> <string name="revanced_hide_creator_store_shelf_title">Yaradıcı mağaza bölümün gizlət</string>
<string name="revanced_hide_creator_store_shelf_summary_on">Yaradıcı alış-veriş cərgəsi video oynadıcı altında gizlidir</string> <string name="revanced_hide_creator_store_shelf_summary_on">Yaradıcı alış-veriş cərgəsi video oynadıcı altında gizlidir</string>
<string name="revanced_hide_creator_store_shelf_summary_off">Yaradıcı alış-veriş cərgəsi video oynadıcı altında görünür</string> <string name="revanced_hide_creator_store_shelf_summary_off">Yaradıcı alış-veriş cərgəsi video oynadıcı altında görünür</string>
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza etiketini gizlət</string> <string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza afişasın gizlət</string>
<string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran alış-veriş etiketi gizlədilib</string> <string name="revanced_hide_end_screen_store_banner_summary_on">Son ekran mağaza afişası gizlidir</string>
<string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran alış-veriş etiketi görünür</string> <string name="revanced_hide_end_screen_store_banner_summary_off">Son ekran mağaza afişası görünür</string>
<string name="revanced_hide_fullscreen_ads_title">Tam ekran reklamlarını gizlət</string> <string name="revanced_hide_fullscreen_ads_title">Tam ekran reklamlarını gizlət</string>
<string name="revanced_hide_fullscreen_ads_summary_on">"Tam ekran reklamları gizlidir <string name="revanced_hide_fullscreen_ads_summary_on">"Tam ekran reklamları gizlidir
@@ -484,9 +484,9 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
<string name="revanced_hide_general_ads_title">Ümumi reklamları gizlət</string> <string name="revanced_hide_general_ads_title">Ümumi reklamları gizlət</string>
<string name="revanced_hide_general_ads_summary_on">Ümumi reklamlar gizlidir</string> <string name="revanced_hide_general_ads_summary_on">Ümumi reklamlar gizlidir</string>
<string name="revanced_hide_general_ads_summary_off">Ümumi reklamlar göstərilir</string> <string name="revanced_hide_general_ads_summary_off">Ümumi reklamlar göstərilir</string>
<string name="revanced_hide_merchandise_banners_title">Məhsul etiketlərini gizlət</string> <string name="revanced_hide_merchandise_banners_title">Məhsul afişaların gizlət</string>
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul etiketləri gizlədilir</string> <string name="revanced_hide_merchandise_banners_summary_on">Məhsul afişaları gizlədilir</string>
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul etiketləri göstərilir</string> <string name="revanced_hide_merchandise_banners_summary_off">Məhsul afişaları görünür</string>
<string name="revanced_hide_paid_promotion_label_title">Ödənişli tanıtım etiketini gizlət</string> <string name="revanced_hide_paid_promotion_label_title">Ödənişli tanıtım etiketini gizlət</string>
<string name="revanced_hide_paid_promotion_label_summary_on">Ödənişli reklam etiketi gizlədilib</string> <string name="revanced_hide_paid_promotion_label_summary_on">Ödənişli reklam etiketi gizlədilib</string>
<string name="revanced_hide_paid_promotion_label_summary_off">Ödənişli reklam etiketi göstərilir</string> <string name="revanced_hide_paid_promotion_label_summary_off">Ödənişli reklam etiketi göstərilir</string>
@@ -496,7 +496,7 @@ Bu xüsusiyyət yalnız köhnə cihazlar üçün mövcuddur"</string>
<string name="revanced_hide_shopping_links_title">Alış-veriş linklərini gizlət</string> <string name="revanced_hide_shopping_links_title">Alış-veriş linklərini gizlət</string>
<string name="revanced_hide_shopping_links_summary_on">Alış-veriş linkləri video təsvirdə gizlidir</string> <string name="revanced_hide_shopping_links_summary_on">Alış-veriş linkləri video təsvirdə gizlidir</string>
<string name="revanced_hide_shopping_links_summary_off">Alış-veriş linkləri video təsvirdə görünür</string> <string name="revanced_hide_shopping_links_summary_off">Alış-veriş linkləri video təsvirdə görünür</string>
<string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” panelin gizlət</string> <string name="revanced_hide_view_products_banner_title">“Məhsullara baxın” afişasın gizlət</string>
<string name="revanced_hide_view_products_banner_summary_on">Məhsullara baxış etiketi video örtüyündə gizlidir</string> <string name="revanced_hide_view_products_banner_summary_on">Məhsullara baxış etiketi video örtüyündə gizlidir</string>
<string name="revanced_hide_view_products_banner_summary_off">Məhsullara baxış etiketi video örtüyündə görünür</string> <string name="revanced_hide_view_products_banner_summary_off">Məhsullara baxış etiketi video örtüyündə görünür</string>
<string name="revanced_hide_web_search_results_title">Veb axtarış nəticələrini gizlət</string> <string name="revanced_hide_web_search_results_title">Veb axtarış nəticələrini gizlət</string>
@@ -1638,10 +1638,6 @@ Video oynatma AV1 ilə ilişə bilər və ya kadrlar buraxıla bilər."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">İstək üçün Statistikada göstər</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">İstək üçün Statistikada göstər</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Qəbuledici növü İstək üçün statistikada göstərilir</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Qəbuledici növü İstək üçün statistikada göstərilir</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Qəbuledici nerd üçün Statistikada gizlidir</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Qəbuledici nerd üçün Statistikada gizlidir</string>
<string name="revanced_spoof_video_streams_language_title">Səs yayım dili</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Xüsusi səs dilini seçmək üçün \"Orijinal səs dilini zorlanı\" qapat</string>
<string name="revanced_spoof_video_streams_language_android_studio">Yayım dili seçimi Android Studio ilə əlçatmazdır</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1640,10 +1640,6 @@ Second \"item\" text"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Паказаць у статыстыцы для спецыялістаў</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Паказаць у статыстыцы для спецыялістаў</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Тып кліента адлюстроўваецца ў статыстыцы для спецыялістаў</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Тып кліента адлюстроўваецца ў статыстыцы для спецыялістаў</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Кліент схаваны ў статыстыцы для спецыялістаў</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Кліент схаваны ў статыстыцы для спецыялістаў</string>
<string name="revanced_spoof_video_streams_language_title">Мова аўдыяпатоку</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Каб выбраць пэўную мову аўдыё, адключыце \'Прымусовая арыгінальная мова аўдыё\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">Выбар мовы трансляцыі недаступны ў Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1639,10 +1639,6 @@ Second \"item\" text"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Poka6i v Statistiki za nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Poka6i v Statistiki za nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Tipът na klienta se poka6va v Statistiki za nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Tipът na klienta se poka6va v Statistiki za nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klientът e skriт v Statistiki za nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klientът e skriт v Statistiki za nerds</string>
<string name="revanced_spoof_video_streams_language_title">Език на аудио потока</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">За да изберете конкретен аудио език, изключете \'Принудително оригинален аудио език\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">Изборът на език на потока не е наличен с Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1635,10 +1635,6 @@ AV1 সহ ভিডিও প্লেব্যাক আটকে যেতে
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">স্ট্যাটস ফর নার্ডসে দেখান</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">স্ট্যাটস ফর নার্ডসে দেখান</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">স্ট্যাটস ফর নার্ডসে ক্লায়েন্ট প্রকার দেখানো হবে</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">স্ট্যাটস ফর নার্ডসে ক্লায়েন্ট প্রকার দেখানো হবে</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">স্ট্যাটস ফর নার্ডসে ক্লায়েন্ট লুকানো হবে</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">স্ট্যাটস ফর নার্ডসে ক্লায়েন্ট লুকানো হবে</string>
<string name="revanced_spoof_video_streams_language_title">অডিও স্ট্রিম ভাষা</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">একটি নির্দিষ্ট অডিও ভাষা নির্বাচন করতে, \'মূল অডিও ভাষা জোর করে চালু রাখুন\' বন্ধ করুন</string>
<string name="revanced_spoof_video_streams_language_android_studio">অ্যান্ড্রয়েড স্টুডিও সহ স্ট্রিম ভাষার নির্বাচন উপলব্ধ নেই</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1639,10 +1639,6 @@ Přehrávání videa s AV1 se může sekat nebo vypadávat snímky."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Zobrazit ve statistikách pro nadšence</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Zobrazit ve statistikách pro nadšence</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Typ klienta se zobrazuje ve statistikách pro nadšence</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Typ klienta se zobrazuje ve statistikách pro nadšence</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klient je skrytý ve statistikách pro nadšence</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klient je skrytý ve statistikách pro nadšence</string>
<string name="revanced_spoof_video_streams_language_title">Jazyk zvukového streamu</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Chcete-li vybrat konkrétní zvukový jazyk, vypněte „Vynutit původní zvukový jazyk“</string>
<string name="revanced_spoof_video_streams_language_android_studio">Volba jazyka streamu není k dispozici s Android Studiem</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1641,10 +1641,6 @@ Videoafspilning med AV1 kan hakke eller tabe billeder."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Vis i Statistik for nørder</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Vis i Statistik for nørder</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Klienttypen vises i Statistik for nørder</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Klienttypen vises i Statistik for nørder</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klienten er skjult i Statistik for nørder</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klienten er skjult i Statistik for nørder</string>
<string name="revanced_spoof_video_streams_language_title">Lydstreamsprog</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">For at vælge et specifikt lydsprog, slå \'Gennemtving originalt lydsprog\' fra</string>
<string name="revanced_spoof_video_streams_language_android_studio">Valg af streaming-sprog er ikke tilgængeligt med Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1636,10 +1636,6 @@ Die Videowiedergabe mit AV1 kann stottern oder Bilder überspringen."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">In Statistiken für Nerds anzeigen</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">In Statistiken für Nerds anzeigen</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Der Client-Typ wird in den Statistiken für Nerds angezeigt</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Der Client-Typ wird in den Statistiken für Nerds angezeigt</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Der Client wird in den Statistiken für Nerds ausgeblendet</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Der Client wird in den Statistiken für Nerds ausgeblendet</string>
<string name="revanced_spoof_video_streams_language_title">Audiodatenstromsprache</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Um eine bestimmte Audiosprache auszuwählen, deaktivieren Sie „Original-Audiosprache erzwingen“</string>
<string name="revanced_spoof_video_streams_language_android_studio">Die Auswahl der Stream-Sprache ist mit Android Studio nicht verfügbar.</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1638,10 +1638,6 @@ Second \"item\" text"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Εμφάνιση στο μενού «Στατιστικά για σπασίκλες»</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Εμφάνιση στο μενού «Στατιστικά για σπασίκλες»</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Το πρόγραμμα πελάτη εμφανίζεται στο μενού «Στατιστικά για σπασίκλες»</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Το πρόγραμμα πελάτη εμφανίζεται στο μενού «Στατιστικά για σπασίκλες»</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Το πρόγραμμα πελάτη δεν εμφανίζεται στο μενού «Στατιστικά για σπασίκλες»</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Το πρόγραμμα πελάτη δεν εμφανίζεται στο μενού «Στατιστικά για σπασίκλες»</string>
<string name="revanced_spoof_video_streams_language_title">Γλώσσα ροής ήχου</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Για να επιλέξετε μια συγκεκριμένη γλώσσα ήχου, απενεργοποιήστε το «Εξαναγκασμός αρχικής γλώσσας ήχου»</string>
<string name="revanced_spoof_video_streams_language_android_studio">Η επιλογή γλώσσας ροής δεν είναι διαθέσιμη με το Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1628,10 +1628,6 @@ La reproducción puede tartamudear o perder fotogramas"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Mostrar en Estadísticas para nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Mostrar en Estadísticas para nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">El tipo de cliente se muestra en Estadísticas para nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">El tipo de cliente se muestra en Estadísticas para nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">El cliente está oculto en Estadísticas para nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">El cliente está oculto en Estadísticas para nerds</string>
<string name="revanced_spoof_video_streams_language_title">Idioma de la transmisión de audio</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Para seleccionar un idioma de audio específico, desactiva \"Forzar idioma de audio original\"</string>
<string name="revanced_spoof_video_streams_language_android_studio">La selección de idioma de transmisión no está disponible con Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1639,10 +1639,6 @@ AV1-ga videotaasesitus võib hakitud olla või kaadreid vahele jätta."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Kuva statistikas \"Nerdide jaoks\"</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Kuva statistikas \"Nerdide jaoks\"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Klienditüüp on statistikas \"Nerdide jaoks\" nähtav</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Klienditüüp on statistikas \"Nerdide jaoks\" nähtav</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klient on statistikas \"Nerdide jaoks\" peidetud</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klient on statistikas \"Nerdide jaoks\" peidetud</string>
<string name="revanced_spoof_video_streams_language_title">Helivoo keel</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Konkreetse helikeele valimiseks lülita välja \"Sunni algne helikeel\"</string>
<string name="revanced_spoof_video_streams_language_android_studio">Voogedastuse keelevalik ei ole Android Studioga saadaval</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -307,7 +307,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1158,13 +1158,13 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
<string name="revanced_sb_segments_highlight_sum">Se osa videota, jota useimmat ihmiset etsivät</string> <string name="revanced_sb_segments_highlight_sum">Se osa videota, jota useimmat ihmiset etsivät</string>
<string name="revanced_sb_segments_intro">Tauko/Introanimaatio</string> <string name="revanced_sb_segments_intro">Tauko/Introanimaatio</string>
<string name="revanced_sb_segments_intro_sum">Aikaväli ilman varsinaista sisältöä. Voi olla tauko, staattinen kehys tai toistuva animaatio. Ei sisällä siirtymiä, jotka sisältävät tietoa</string> <string name="revanced_sb_segments_intro_sum">Aikaväli ilman varsinaista sisältöä. Voi olla tauko, staattinen kehys tai toistuva animaatio. Ei sisällä siirtymiä, jotka sisältävät tietoa</string>
<string name="revanced_sb_segments_outro">Loppukortit / Tekijätiedot</string> <string name="revanced_sb_segments_outro">Loppukortit / -tekstit</string>
<string name="revanced_sb_segments_outro_sum">Lopputekstit tai kun YouTuben loppukortit tulevat näkyviin. Ei lopetuksille, joissa on tietoa</string> <string name="revanced_sb_segments_outro_sum">Lopputekstit tai kun YouTuben loppukortit tulevat näkyviin. Ei lopetuksille, joissa on tietoa</string>
<string name="revanced_sb_segments_hook">Koukku / Tervehdykset</string> <string name="revanced_sb_segments_hook">Koukku / Tervehdykset</string>
<string name="revanced_sb_segments_hook_sum">Kertovat trailerit tulevasta videosta, tervehdykset ja hyvästelyt. Ei sisällä osioita, jotka lisäävät lisäsisältöä</string> <string name="revanced_sb_segments_hook_sum">Kertovat trailerit tulevasta videosta, tervehdykset ja hyvästelyt. Ei sisällä osioita, jotka lisäävät lisäsisältöä</string>
<string name="revanced_sb_segments_preview">Esikatselu / Yhteenveto</string> <string name="revanced_sb_segments_preview">Esikatselu / Kertaus</string>
<string name="revanced_sb_segments_preview_sum">Kokoelma leikkeitä, jotka osoittavat, mitä on tulossa tai mitä tapahtui videossa tai muissa sarjan videoissa, joiden kaikki informaatio toistuu muualla</string> <string name="revanced_sb_segments_preview_sum">Kokoelma leikkeitä, jotka osoittavat, mitä on tulossa tai mitä tapahtui videossa tai muissa sarjan videoissa, joiden kaikki informaatio toistuu muualla</string>
<string name="revanced_sb_segments_filler">Tangentti / Vitsit</string> <string name="revanced_sb_segments_filler">Toissijaiset kohtaukset / Vitsit</string>
<string name="revanced_sb_segments_filler_sum">Epäolennaiset kohtaukset tai vitsit, joita ei tarvita videon pääsisällön ymmärtämiseen. Ei sisällä osioita, jotka tarjoavat kontekstia tai taustatietoja</string> <string name="revanced_sb_segments_filler_sum">Epäolennaiset kohtaukset tai vitsit, joita ei tarvita videon pääsisällön ymmärtämiseen. Ei sisällä osioita, jotka tarjoavat kontekstia tai taustatietoja</string>
<string name="revanced_sb_segments_nomusic">Musiikki: Musiikiton osa</string> <string name="revanced_sb_segments_nomusic">Musiikki: Musiikiton osa</string>
<string name="revanced_sb_segments_nomusic_sum">Vain musiikkivideoille. Musiikkivideoiden osiot ilman musiikkia, jotka eivät jo kuulu toiseen kategoriaan</string> <string name="revanced_sb_segments_nomusic_sum">Vain musiikkivideoille. Musiikkivideoiden osiot ilman musiikkia, jotka eivät jo kuulu toiseen kategoriaan</string>
@@ -1182,7 +1182,7 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
<string name="revanced_sb_skip_button_preview_beginning">Ohita esikatselu</string> <string name="revanced_sb_skip_button_preview_beginning">Ohita esikatselu</string>
<string name="revanced_sb_skip_button_preview_middle">Ohita esikatselu</string> <string name="revanced_sb_skip_button_preview_middle">Ohita esikatselu</string>
<string name="revanced_sb_skip_button_preview_end">Ohita kertaus</string> <string name="revanced_sb_skip_button_preview_end">Ohita kertaus</string>
<string name="revanced_sb_skip_button_filler">Ohita Tangentti</string> <string name="revanced_sb_skip_button_filler">Ohita toissijainen kohtaus</string>
<string name="revanced_sb_skip_button_nomusic">Ohita musiikiton</string> <string name="revanced_sb_skip_button_nomusic">Ohita musiikiton</string>
<string name="revanced_sb_skip_button_unsubmitted">Ohita osio</string> <string name="revanced_sb_skip_button_unsubmitted">Ohita osio</string>
<string name="revanced_sb_skipped_sponsor">Sponsori ohitettiin</string> <string name="revanced_sb_skipped_sponsor">Sponsori ohitettiin</string>
@@ -1193,11 +1193,11 @@ UserID on kuin salasana, eikä sitä pidä jakaa kenellekään.
<string name="revanced_sb_skipped_intro_middle">Tauko ohitettiin</string> <string name="revanced_sb_skipped_intro_middle">Tauko ohitettiin</string>
<string name="revanced_sb_skipped_intro_end">Tauko ohitettiin</string> <string name="revanced_sb_skipped_intro_end">Tauko ohitettiin</string>
<string name="revanced_sb_skipped_outro">Outro ohitettiin</string> <string name="revanced_sb_skipped_outro">Outro ohitettiin</string>
<string name="revanced_sb_skipped_hook">Ohitettu koukku</string> <string name="revanced_sb_skipped_hook">Koukku ohitettiin</string>
<string name="revanced_sb_skipped_preview_beginning">Esikatselu ohitettiin</string> <string name="revanced_sb_skipped_preview_beginning">Esikatselu ohitettiin</string>
<string name="revanced_sb_skipped_preview_middle">Esikatselu ohitettiin</string> <string name="revanced_sb_skipped_preview_middle">Esikatselu ohitettiin</string>
<string name="revanced_sb_skipped_preview_end">Kertaus ohitettiin</string> <string name="revanced_sb_skipped_preview_end">Kertaus ohitettiin</string>
<string name="revanced_sb_skipped_filler">Ohitettu tangentti</string> <string name="revanced_sb_skipped_filler">Toissijainen kohtaus ohitettiin</string>
<string name="revanced_sb_skipped_nomusic">Musiikiton osio ohitettiin</string> <string name="revanced_sb_skipped_nomusic">Musiikiton osio ohitettiin</string>
<string name="revanced_sb_skipped_unsubmitted">Lähettämätön osio ohitettiin</string> <string name="revanced_sb_skipped_unsubmitted">Lähettämätön osio ohitettiin</string>
<string name="revanced_sb_skipped_multiple_segments">Useita osioita ohitettiin</string> <string name="revanced_sb_skipped_multiple_segments">Useita osioita ohitettiin</string>
@@ -1254,7 +1254,7 @@ Oletko valmis lähettämään?"</string>
<string name="revanced_sb_new_segment_edit_by_hand_parse_error">Annettu aika on virheellinen</string> <string name="revanced_sb_new_segment_edit_by_hand_parse_error">Annettu aika on virheellinen</string>
<string name="revanced_sb_stats_title">Tilastot</string> <string name="revanced_sb_stats_title">Tilastot</string>
<!-- Shown in the settings preferences, and translations can be any text length. --> <!-- Shown in the settings preferences, and translations can be any text length. -->
<string name="revanced_sb_stats_connection_failure">Tilastot eivät tilapäisesti saatavilla (API ei ole käytettävissä)</string> <string name="revanced_sb_stats_connection_failure">Tilastot eivät ole tilapäisesti saatavilla (API ei ole käytettävissä)</string>
<string name="revanced_sb_stats_loading">Ladataan...</string> <string name="revanced_sb_stats_loading">Ladataan...</string>
<string name="revanced_sb_stats_sb_disabled">SponsorBlock ei ole käytössä</string> <string name="revanced_sb_stats_sb_disabled">SponsorBlock ei ole käytössä</string>
<string name="revanced_sb_stats_username">Käyttäjänimesi: &lt;b&gt;%s&lt;/b&gt;</string> <string name="revanced_sb_stats_username">Käyttäjänimesi: &lt;b&gt;%s&lt;/b&gt;</string>
@@ -1265,11 +1265,11 @@ Oletko valmis lähettämään?"</string>
<string name="revanced_sb_stats_submissions">Olet luonut &lt;b&gt;%s&lt;/b&gt; osiota</string> <string name="revanced_sb_stats_submissions">Olet luonut &lt;b&gt;%s&lt;/b&gt; osiota</string>
<string name="revanced_sb_stats_submissions_sum">Napauta tästä nähdäksesi osiosi</string> <string name="revanced_sb_stats_submissions_sum">Napauta tästä nähdäksesi osiosi</string>
<string name="revanced_sb_stats_saved_zero">SponsorBlock-tulostaulu</string> <string name="revanced_sb_stats_saved_zero">SponsorBlock-tulostaulu</string>
<string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä &lt;b&gt;%s&lt;/b&gt; segmentiltä</string> <string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä &lt;b&gt;%s&lt;/b&gt; osiolta</string>
<string name="revanced_sb_stats_saved_sum_zero">Napauta tästä nähdäksesi globaalit tilastot ja parhaat osallistujat</string> <string name="revanced_sb_stats_saved_sum_zero">Napauta tästä nähdäksesi globaalit tilastot ja parhaat osallistujat</string>
<string name="revanced_sb_stats_saved_sum">Se on &lt;b&gt;%s&lt;/b&gt; heidän elämistään.&lt;br&gt;Napauta tästä nähdäksesi tulostaulun</string> <string name="revanced_sb_stats_saved_sum">Se on &lt;b&gt;%s&lt;/b&gt; heidän elämistään.&lt;br&gt;Napauta tästä nähdäksesi tulostaulun</string>
<string name="revanced_sb_stats_self_saved">Olet ohittanut &lt;b&gt;%s&lt;/b&gt; osiota</string> <string name="revanced_sb_stats_self_saved">Olet ohittanut &lt;b&gt;%s&lt;/b&gt; osiota</string>
<string name="revanced_sb_stats_self_saved_sum">Tuo on &lt;b&gt;%s&lt;/b&gt;</string> <string name="revanced_sb_stats_self_saved_sum">Se on &lt;b&gt;%s&lt;/b&gt;</string>
<string name="revanced_sb_stats_self_saved_reset_title">Nollataanko ohitettujen osioiden laskuri?</string> <string name="revanced_sb_stats_self_saved_reset_title">Nollataanko ohitettujen osioiden laskuri?</string>
<string name="revanced_sb_stats_saved_hour_format">%1$s tuntia %2$s minuuttia</string> <string name="revanced_sb_stats_saved_hour_format">%1$s tuntia %2$s minuuttia</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s minuuttia %2$s sekuntia</string> <string name="revanced_sb_stats_saved_minute_format">%1$s minuuttia %2$s sekuntia</string>
@@ -1639,10 +1639,6 @@ AV1-videon toisto saattaa pätkiä."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Näytä teknisissä tiedoissa</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Näytä teknisissä tiedoissa</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Asiakastyyppi näytetään teknisissä tiedoissa</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Asiakastyyppi näytetään teknisissä tiedoissa</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Asiakastyyppi piilotetaan teknisissä tiedoissa</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Asiakastyyppi piilotetaan teknisissä tiedoissa</string>
<string name="revanced_spoof_video_streams_language_title">Äänivirran kieli</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Valitaksesi tietyn äänen kielen, poista \"Pakota alkuperäinen äänen kieli\" käytöstä</string>
<string name="revanced_spoof_video_streams_language_android_studio">Striimin kielivalinta ei ole käytettävissä Android Studion kanssa</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1637,10 +1637,6 @@ Maaaring mag-stutter o mag-drop ng frames ang pag-playback ng video na may AV1."
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Ipakita sa Mga Istatistika para sa mga nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Ipakita sa Mga Istatistika para sa mga nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Ipinapakita ang uri ng kliyente sa Mga Istatistika para sa mga nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Ipinapakita ang uri ng kliyente sa Mga Istatistika para sa mga nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Nakatago ang kliyente sa Mga Istatistika para sa mga nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Nakatago ang kliyente sa Mga Istatistika para sa mga nerds</string>
<string name="revanced_spoof_video_streams_language_title">Wika ng audio stream</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Upang pumili ng isang partikular na wika ng audio, i-off ang \'Puwersahin ang orihinal na wika ng audio\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">Hindi available ang pagpili ng wika ng stream sa Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -26,12 +26,12 @@ Second \"item\" text"</string>
<!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 --> <!-- Translations of this should be identical to revanced_custom_branding_icon_entry_5 -->
<string name="revanced_custom_branding_name_entry_5">Personnalisé</string> <string name="revanced_custom_branding_name_entry_5">Personnalisé</string>
<string name="revanced_custom_branding_icon_title">Icône de l\'application</string> <string name="revanced_custom_branding_icon_title">Icône de l\'application</string>
<string name="revanced_custom_branding_icon_entry_1">Original</string> <string name="revanced_custom_branding_icon_entry_1">Originale</string>
<!-- Translation of this should be identical to revanced_header_logo_entry_5 --> <!-- Translation of this should be identical to revanced_header_logo_entry_5 -->
<string name="revanced_custom_branding_icon_entry_3">ReVanced minimaliste</string> <string name="revanced_custom_branding_icon_entry_3">ReVanced minimaliste</string>
<string name="revanced_custom_branding_icon_entry_4">ReVanced mis à l\'échelle</string> <string name="revanced_custom_branding_icon_entry_4">ReVanced mise à l\'échelle</string>
<!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 --> <!-- Translations of this should be identical to revanced_custom_branding_name_entry_5 -->
<string name="revanced_custom_branding_icon_entry_5">Personnalisé</string> <string name="revanced_custom_branding_icon_entry_5">Personnalisée</string>
</patch> </patch>
<patch id="misc.checks.checkEnvironmentPatch"> <patch id="misc.checks.checkEnvironmentPatch">
<string name="revanced_check_environment_failed_title">Les vérifications ont échoué</string> <string name="revanced_check_environment_failed_title">Les vérifications ont échoué</string>
@@ -1363,7 +1363,7 @@ Limitation : Il se peut que le bouton Retour dans la barre d'outils ne fonction
</patch> </patch>
<patch id="layout.miniplayer.miniplayerPatch"> <patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">Lecteur réduit</string> <string name="revanced_miniplayer_screen_title">Lecteur réduit</string>
<string name="revanced_miniplayer_screen_summary">Modifier le style du lecteur réduit à l\'intérieur de l\'application</string> <string name="revanced_miniplayer_screen_summary">Modifiez le style du lecteur réduit intégré à l\'application</string>
<string name="revanced_miniplayer_type_title">Type de lecteur réduit</string> <string name="revanced_miniplayer_type_title">Type de lecteur réduit</string>
<string name="revanced_miniplayer_type_entry_0">Désactivé</string> <string name="revanced_miniplayer_type_entry_0">Désactivé</string>
<string name="revanced_miniplayer_type_entry_1">Par défaut</string> <string name="revanced_miniplayer_type_entry_1">Par défaut</string>
@@ -1623,11 +1623,11 @@ Limitations :
<string name="revanced_spoof_video_streams_av1_title">Autoriser Android VR AV1</string> <string name="revanced_spoof_video_streams_av1_title">Autoriser Android VR AV1</string>
<string name="revanced_spoof_video_streams_av1_summary_on">"Le codec vidéo est AVC (H.264), VP9 ou AV1 <string name="revanced_spoof_video_streams_av1_summary_on">"Le codec vidéo est AVC (H.264), VP9 ou AV1
La lecture peut saccader ou perdre des images"</string> La lecture peut être saccadée et des images peuvent être perdues"</string>
<string name="revanced_spoof_video_streams_av1_summary_off">Le codec vidéo est AVC (H.264) ou VP9</string> <string name="revanced_spoof_video_streams_av1_summary_off">Le codec vidéo est AVC (H.264) ou VP9</string>
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"L'activation de ce paramètre peut utiliser le décodage AV1 logiciel. <string name="revanced_spoof_video_streams_av1_user_dialog_message">"L'activation de ce paramètre permet l'utilisation du décodage AV1 logiciel.
La lecture vidéo avec AV1 peut saccader ou perdre des images."</string> La lecture vidéo avec AV1 peut être saccadée et des images peuvent être perdues."</string>
<string name="revanced_spoof_video_streams_about_title">Effets secondaires de la falsification</string> <string name="revanced_spoof_video_streams_about_title">Effets secondaires de la falsification</string>
<string name="revanced_spoof_video_streams_about_experimental">• Client expérimental, peut cesser de fonctionner à tout moment</string> <string name="revanced_spoof_video_streams_about_experimental">• Client expérimental, peut cesser de fonctionner à tout moment</string>
<string name="revanced_spoof_video_streams_about_playback_failure">• Les vidéos sont susceptibles de s\'arrêter à 1:00, ou de ne pas être disponibles dans certaines régions</string> <string name="revanced_spoof_video_streams_about_playback_failure">• Les vidéos sont susceptibles de s\'arrêter à 1:00, ou de ne pas être disponibles dans certaines régions</string>
@@ -1640,10 +1640,6 @@ La lecture vidéo avec AV1 peut saccader ou perdre des images."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Afficher dans les Statistiques avancées</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Afficher dans les Statistiques avancées</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Le type de client est affiché dans les Statistiques avancées</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Le type de client est affiché dans les Statistiques avancées</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Le client est caché dans les Statistiques avancées</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Le client est caché dans les Statistiques avancées</string>
<string name="revanced_spoof_video_streams_language_title">Langue du flux audio</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Pour sélectionner une langue audio spécifique, désactivez \"Forcer la langue audio d\'origine\"</string>
<string name="revanced_spoof_video_streams_language_android_studio">La sélection de la langue du flux n\'est pas disponible avec Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -259,7 +259,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -258,7 +258,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1636,10 +1636,6 @@ Az AV1-es videólejátszás akadozhat vagy képkockákat ejthet."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Megjelenítés a Statisztikákban</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Megjelenítés a Statisztikákban</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">A kliens típusa a Statisztikákban látható</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">A kliens típusa a Statisztikákban látható</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">A kliens el van rejtve a Statisztikákban</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">A kliens el van rejtve a Statisztikákban</string>
<string name="revanced_spoof_video_streams_language_title">Hangfolyam nyelve</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Egy adott hangsáv nyelv kiválasztásához kapcsold ki az \"Eredeti hangsáv nyelv kikényszerítése\" opciót</string>
<string name="revanced_spoof_video_streams_language_android_studio">Az Android Studio-val nem érhető el a stream nyelvének kiválasztása</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1640,10 +1640,6 @@ AV1-ով տեսանյութի նվագարկումը կարող է ընդհատ
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Ցուցադրել վիճակագրության ակնոցներում</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Ցուցադրել վիճակագրության ակնոցներում</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Հաճախորդի տեսակը ցուցադրվում է վիճակագրության ակնոցներում</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Հաճախորդի տեսակը ցուցադրվում է վիճակագրության ակնոցներում</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Հաճախորդը թաքնված է վիճակագրության ակնոցներում</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Հաճախորդը թաքնված է վիճակագրության ակնոցներում</string>
<string name="revanced_spoof_video_streams_language_title">Ձայնային հոսքի լեզուն</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Որոշակի ձայնային լեզու ընտրելու համար անջատեք \'Պարտադրել բնօրինակ ձայնային լեզուն\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">Հոսքի լեզվի ընտրությունը հասանելի չէ Android Studio-ի հետ</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1638,10 +1638,6 @@ Pemutaran video dengan AV1 mungkin tersendat atau kehilangan bingkai."</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Tampilkan di Statistik untuk nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Tampilkan di Statistik untuk nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Jenis klien ditampilkan di Statistik untuk nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Jenis klien ditampilkan di Statistik untuk nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klien disembunyikan di Statistik untuk nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Klien disembunyikan di Statistik untuk nerds</string>
<string name="revanced_spoof_video_streams_language_title">Bahasa aliran audio</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Untuk memilih bahasa audio tertentu, matikan \'Paksa bahasa audio asli\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">Pilihan bahasa streaming tidak tersedia dengan Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -257,7 +257,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title --> <!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1638,10 +1638,6 @@ La riproduzione video con AV1 potrebbe rallentare o perdere fotogrammi."</string
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Mostra nelle statistiche per nerd</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Mostra nelle statistiche per nerd</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Il tipo di client è mostrato nelle statistiche per nerd</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Il tipo di client è mostrato nelle statistiche per nerd</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Il client è nascosto nelle statistiche per nerd</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Il client è nascosto nelle statistiche per nerd</string>
<string name="revanced_spoof_video_streams_language_title">Lingua del flusso audio</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">Per selezionare una lingua audio specifica, disattiva \'Forza lingua audio originale\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">La selezione della lingua dello stream non è disponibile con Android Studio</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024 ReVanced. Not licensed under GPL. See https://github.com/ReVanced/revanced-branding --> <!-- Copyright 2024 ReVanced. 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. All strings must have a unique path, even if the same string is declared in two different apps.
@@ -1641,10 +1641,6 @@ Second \"item\" text"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">הצג בנתונים לגיקים</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">הצג בנתונים לגיקים</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">סוג הלקוח מוצג בנתונים לגיקים</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">סוג הלקוח מוצג בנתונים לגיקים</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">הלקוח מוסתר בנתונים לגיקים</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">הלקוח מוסתר בנתונים לגיקים</string>
<string name="revanced_spoof_video_streams_language_title">שפת זרם השמע</string>
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
<string name="revanced_spoof_video_streams_language_not_available">כדי לבחור שפת שמע ספציפית, כבה את \'אכוף שפת שמע מקורית\'</string>
<string name="revanced_spoof_video_streams_language_android_studio">בחירת שפת הזרם אינה זמינה עם אנדרואיד סטודיו</string>
</patch> </patch>
</app> </app>
<app id="music"> <app id="music">

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