mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 18:03:55 +01:00
Compare commits
68 Commits
v5.43.0-de
...
v5.46.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce503d5b58 | ||
|
|
57263538c7 | ||
|
|
70f4955e89 | ||
|
|
582144026d | ||
|
|
d80892cc0e | ||
|
|
6c4b931b8a | ||
|
|
76dcfaefd8 | ||
|
|
e4f52343c0 | ||
|
|
1196b1a147 | ||
|
|
858edbf3e7 | ||
|
|
a52c0153b1 | ||
|
|
cd9ef81354 | ||
|
|
1b2cd64a86 | ||
|
|
0c03599f07 | ||
|
|
5f23bfe833 | ||
|
|
2cf8f0e636 | ||
|
|
c17cf98c7e | ||
|
|
3e4990afff | ||
|
|
292fae440c | ||
|
|
12e7c0943a | ||
|
|
a0c5604951 | ||
|
|
38d9299dfe | ||
|
|
dfdbbfa047 | ||
|
|
e9f45ce926 | ||
|
|
1b38b1a3c8 | ||
|
|
13cf1724bf | ||
|
|
6d01863ec7 | ||
|
|
a32ed30b4c | ||
|
|
ef44eaa119 | ||
|
|
c73a03c9e1 | ||
|
|
c1681f982a | ||
|
|
1502bf7524 | ||
|
|
dffb1e6525 | ||
|
|
b8c2ede2bf | ||
|
|
591e106098 | ||
|
|
e7336d2ef3 | ||
|
|
7a53f8f62d | ||
|
|
3466d9d210 | ||
|
|
876d7a6b03 | ||
|
|
a2aa9cac27 | ||
|
|
08baa19b4a | ||
|
|
7283b93cea | ||
|
|
754b71959a | ||
|
|
c64e29ec57 | ||
|
|
b2dd008aee | ||
|
|
de97562c5d | ||
|
|
6373829fd6 | ||
|
|
cfd244b408 | ||
|
|
e8e28e2b6a | ||
|
|
2e4c6fdcad | ||
|
|
644d6dcb51 | ||
|
|
14dd7346a8 | ||
|
|
0af8c8a766 | ||
|
|
96454c843b | ||
|
|
476ef0fae1 | ||
|
|
bbec724afb | ||
|
|
7a1dcbd4ee | ||
|
|
2a1e31860f | ||
|
|
949d6bdd19 | ||
|
|
7563990750 | ||
|
|
4b605eb270 | ||
|
|
c2d7a7fb8b | ||
|
|
a55560dc25 | ||
|
|
e8522d703e | ||
|
|
068d029a03 | ||
|
|
0c19dbaf30 | ||
|
|
bf73ac8316 | ||
|
|
95eee59a87 |
218
CHANGELOG.md
218
CHANGELOG.md
@@ -1,3 +1,221 @@
|
||||
# [5.46.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.46.0-dev.3...v5.46.0-dev.4) (2025-11-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Check watch history domain name resolution:** Fix false positive warning message if the internet connection fails halfway into the DNS check ([5726353](https://github.com/ReVanced/revanced-patches/commit/57263538c79f5a561c449229ac8e068c641285d3))
|
||||
|
||||
# [5.46.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.46.0-dev.2...v5.46.0-dev.3) (2025-11-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide layout components:** Fix "Hide Hype points" ([#6247](https://github.com/ReVanced/revanced-patches/issues/6247)) ([5821440](https://github.com/ReVanced/revanced-patches/commit/582144026d28e57bb7adcbba39244f3c7cdbc0f3))
|
||||
|
||||
# [5.46.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.46.0-dev.1...v5.46.0-dev.2) (2025-11-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Settings:** Resolve settings search crash when searching for specific words ([#6231](https://github.com/ReVanced/revanced-patches/issues/6231)) ([76dcfae](https://github.com/ReVanced/revanced-patches/commit/76dcfaefd8679e45a70f265b0239436e60c055cf))
|
||||
|
||||
# [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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))
|
||||
|
||||
# [5.43.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.2...v5.43.0-dev.3) (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))
|
||||
|
||||
# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14)
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@ public class HideCastButtonPatch {
|
||||
* Injection point
|
||||
*/
|
||||
public static void hideCastButton(View view) {
|
||||
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view);
|
||||
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON, view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
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;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@@ -8,7 +11,7 @@ public class HideCategoryBarPatch {
|
||||
/**
|
||||
* Injection point
|
||||
*/
|
||||
public static boolean hideCategoryBar() {
|
||||
return Settings.HIDE_CATEGORY_BAR.get();
|
||||
public static void hideCategoryBar(View view) {
|
||||
hideViewBy0dpUnderCondition(Settings.HIDE_CATEGORY_BAR, view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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.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_61_48;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
|
||||
@@ -18,8 +19,9 @@ public class SpoofVideoStreamsPatch {
|
||||
public static void setClientOrderToUse() {
|
||||
List<ClientType> availableClients = List.of(
|
||||
ANDROID_VR_1_43_32,
|
||||
ANDROID_VR_1_61_48,
|
||||
VISIONOS
|
||||
ANDROID_NO_SDK,
|
||||
VISIONOS,
|
||||
ANDROID_VR_1_61_48
|
||||
);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
|
||||
4
extensions/samsung/radio/build.gradle.kts
Normal file
4
extensions/samsung/radio/build.gradle.kts
Normal file
@@ -0,0 +1,4 @@
|
||||
dependencies {
|
||||
compileOnly(project(":extensions:shared:library"))
|
||||
compileOnly(project(":extensions:samsung:radio:stub"))
|
||||
}
|
||||
1
extensions/samsung/radio/src/main/AndroidManifest.xml
Normal file
1
extensions/samsung/radio/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
17
extensions/samsung/radio/stub/build.gradle.kts
Normal file
17
extensions/samsung/radio/stub/build.gradle.kts
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,7 @@
|
||||
package android.os;
|
||||
|
||||
public class SemSystemProperties {
|
||||
public static String getSalesCode() {
|
||||
throw new UnsupportedOperationException("Stub");
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.text.Bidi;
|
||||
import java.text.Collator;
|
||||
import java.text.Normalizer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -79,6 +81,15 @@ public class Utils {
|
||||
@Nullable
|
||||
private static Boolean isDarkModeEnabled;
|
||||
|
||||
// Cached Collator instance with its locale.
|
||||
@Nullable
|
||||
private static Locale cachedCollatorLocale;
|
||||
@Nullable
|
||||
private static Collator cachedCollator;
|
||||
|
||||
private static final Pattern PUNCTUATION_PATTERN = Pattern.compile("\\p{P}+");
|
||||
private static final Pattern DIACRITICS_PATTERN = Pattern.compile("\\p{M}");
|
||||
|
||||
private Utils() {
|
||||
} // utility class
|
||||
|
||||
@@ -976,30 +987,60 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern punctuationPattern = Pattern.compile("\\p{P}+");
|
||||
|
||||
/**
|
||||
* Strips all punctuation and converts to lower case. A null parameter returns an empty string.
|
||||
* Removes punctuation and converts text to lowercase. Returns an empty string if input is null.
|
||||
*/
|
||||
public static String removePunctuationToLowercase(@Nullable CharSequence original) {
|
||||
if (original == null) return "";
|
||||
return punctuationPattern.matcher(original).replaceAll("")
|
||||
return PUNCTUATION_PATTERN.matcher(original).replaceAll("")
|
||||
.toLowerCase(BaseSettings.REVANCED_LANGUAGE.get().getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort a PreferenceGroup and all it's sub groups by title or key.
|
||||
* Normalizes text for search: applies NFD, removes diacritics, and lowercases (locale-neutral).
|
||||
* Returns an empty string if input is null.
|
||||
*/
|
||||
public static String normalizeTextToLowercase(@Nullable CharSequence original) {
|
||||
if (original == null) return "";
|
||||
return DIACRITICS_PATTERN.matcher(Normalizer.normalize(original, Normalizer.Form.NFD))
|
||||
.replaceAll("").toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cached Collator for the current locale, or creates a new one if locale changed.
|
||||
*/
|
||||
private static Collator getCollator() {
|
||||
Locale currentLocale = BaseSettings.REVANCED_LANGUAGE.get().getLocale();
|
||||
|
||||
if (cachedCollator == null || !currentLocale.equals(cachedCollatorLocale)) {
|
||||
cachedCollatorLocale = currentLocale;
|
||||
cachedCollator = Collator.getInstance(currentLocale);
|
||||
cachedCollator.setStrength(Collator.SECONDARY); // Case-insensitive, diacritic-insensitive.
|
||||
}
|
||||
|
||||
return cachedCollator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a {@link PreferenceGroup} and all nested subgroups by title or key.
|
||||
* <p>
|
||||
* Sort order is determined by the preferences key {@link Sort} suffix.
|
||||
* The sort order is controlled by the {@link Sort} suffix present in the preference key.
|
||||
* Preferences without a key or without a {@link Sort} suffix remain in their original order.
|
||||
* <p>
|
||||
* If a preference has no key or no {@link Sort} suffix,
|
||||
* then the preferences are left unsorted.
|
||||
* Sorting is performed using {@link Collator} with the current user locale,
|
||||
* ensuring correct alphabetical ordering for all supported languages
|
||||
* (e.g., Ukrainian "і", German "ß", French accented characters, etc.).
|
||||
*
|
||||
* @param group the {@link PreferenceGroup} to sort
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void sortPreferenceGroups(PreferenceGroup group) {
|
||||
Sort groupSort = Sort.fromKey(group.getKey(), Sort.UNSORTED);
|
||||
List<Pair<String, Preference>> preferences = new ArrayList<>();
|
||||
|
||||
// Get cached Collator for locale-aware string comparison.
|
||||
Collator collator = getCollator();
|
||||
|
||||
for (int i = 0, prefCount = group.getPreferenceCount(); i < prefCount; i++) {
|
||||
Preference preference = group.getPreference(i);
|
||||
|
||||
@@ -1030,10 +1071,11 @@ public class Utils {
|
||||
preferences.add(new Pair<>(sortValue, preference));
|
||||
}
|
||||
|
||||
//noinspection ComparatorCombinators
|
||||
// Sort the list using locale-specific collation rules.
|
||||
Collections.sort(preferences, (pair1, pair2)
|
||||
-> pair1.first.compareTo(pair2.first));
|
||||
-> collator.compare(pair1.first, pair2.first));
|
||||
|
||||
// Reassign order values to reflect the new sorted sequence
|
||||
int index = 0;
|
||||
for (Pair<String, Preference> pair : preferences) {
|
||||
int order = index++;
|
||||
|
||||
@@ -61,7 +61,11 @@ public class CheckWatchHistoryDomainNameResolutionPatch {
|
||||
// Prevent this false positive by verify youtube.com resolves.
|
||||
// If youtube.com does not resolve, then it's not a watch history domain resolving error
|
||||
// because the entire app will not work since no domains are resolving.
|
||||
if (!domainResolvesToValidIP("youtube.com")
|
||||
String domainYouTube = "youtube.com";
|
||||
if (!domainResolvesToValidIP(domainYouTube)
|
||||
|| domainResolvesToValidIP(HISTORY_TRACKING_ENDPOINT)
|
||||
// Check multiple times, so a false positive from a flaky connection is almost impossible.
|
||||
|| !domainResolvesToValidIP(domainYouTube)
|
||||
|| domainResolvesToValidIP(HISTORY_TRACKING_ENDPOINT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -150,14 +150,14 @@ public class CustomBrandingPatch {
|
||||
}
|
||||
|
||||
for (ComponentName disable : componentsToDisable) {
|
||||
// Use info logging because if the alias status become corrupt the app cannot launch.
|
||||
Logger.printInfo(() -> "Disabling: " + disable.getClassName());
|
||||
pm.setComponentEnabledSetting(disable,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
|
||||
}
|
||||
|
||||
// Use info logging because if the alias status become corrupt the app cannot launch.
|
||||
ComponentName componentToEnableFinal = componentToEnable;
|
||||
Logger.printInfo(() -> "Enabling: " + componentToEnableFinal.getClassName());
|
||||
|
||||
pm.setComponentEnabledSetting(componentToEnable,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -17,9 +17,6 @@ public class LinkSanitizer {
|
||||
|
||||
public LinkSanitizer(String ... parametersToRemove) {
|
||||
final int parameterCount = parametersToRemove.length;
|
||||
if (parameterCount == 0) {
|
||||
throw new IllegalArgumentException("No parameters specified");
|
||||
}
|
||||
|
||||
// List is faster if only checking a few parameters.
|
||||
this.parametersToRemove = parameterCount > 4
|
||||
@@ -40,10 +37,12 @@ public class LinkSanitizer {
|
||||
try {
|
||||
Uri.Builder builder = uri.buildUpon().clearQuery();
|
||||
|
||||
for (String paramName : uri.getQueryParameterNames()) {
|
||||
if (!parametersToRemove.contains(paramName)) {
|
||||
for (String value : uri.getQueryParameters(paramName)) {
|
||||
builder.appendQueryParameter(paramName, value);
|
||||
if (!parametersToRemove.isEmpty()) {
|
||||
for (String paramName : uri.getQueryParameterNames()) {
|
||||
if (!parametersToRemove.contains(paramName)) {
|
||||
for (String value : uri.getQueryParameters(paramName)) {
|
||||
builder.appendQueryParameter(paramName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.shared.patches.CustomBrandingPatch.BrandingTheme;
|
||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
|
||||
|
||||
/**
|
||||
* 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 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 SANITIZE_SHARED_LINKS = new BooleanSetting("revanced_sanitize_sharing_links", TRUE);
|
||||
|
||||
@@ -392,10 +392,13 @@ public abstract class Setting<T> {
|
||||
|
||||
/**
|
||||
* Get the parent Settings that this setting depends on.
|
||||
* @return List of parent Settings (e.g., BooleanSetting or EnumSetting), or empty list if no dependencies exist.
|
||||
* @return List of parent Settings, or empty list if no dependencies exist.
|
||||
* Defensive: handles null availability or missing getParentSettings() override.
|
||||
*/
|
||||
public List<Setting<?>> getParentSettings() {
|
||||
return availability == null ? Collections.emptyList() : availability.getParentSettings();
|
||||
return availability == null
|
||||
? Collections.emptyList()
|
||||
: Objects.requireNonNullElse(availability.getParentSettings(), Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class BaseSearchResultItem {
|
||||
|
||||
// Shared method for highlighting text with search query.
|
||||
protected static CharSequence highlightSearchQuery(CharSequence text, Pattern queryPattern) {
|
||||
if (TextUtils.isEmpty(text)) return text;
|
||||
if (TextUtils.isEmpty(text) || queryPattern == null) return text;
|
||||
|
||||
final int adjustedColor = Utils.adjustColorBrightness(
|
||||
Utils.getAppBackgroundColor(), 0.95f, 1.20f);
|
||||
@@ -84,7 +84,10 @@ public abstract class BaseSearchResultItem {
|
||||
|
||||
Matcher matcher = queryPattern.matcher(text);
|
||||
while (matcher.find()) {
|
||||
spannable.setSpan(highlightSpan, matcher.start(), matcher.end(),
|
||||
int start = matcher.start();
|
||||
int end = matcher.end();
|
||||
if (start == end) continue; // Skip zero matches.
|
||||
spannable.setSpan(highlightSpan, start, end,
|
||||
SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
@@ -224,10 +227,14 @@ public abstract class BaseSearchResultItem {
|
||||
return searchBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends normalized searchable text to the builder.
|
||||
* Uses full Unicode normalization for accurate search across all languages.
|
||||
*/
|
||||
private void appendText(StringBuilder builder, CharSequence text) {
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
if (builder.length() > 0) builder.append(" ");
|
||||
builder.append(Utils.removePunctuationToLowercase(text));
|
||||
builder.append(Utils.normalizeTextToLowercase(text));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,7 +279,7 @@ public abstract class BaseSearchResultItem {
|
||||
*/
|
||||
@Override
|
||||
boolean matchesQuery(String query) {
|
||||
return searchableText.contains(Utils.removePunctuationToLowercase(query));
|
||||
return searchableText.contains(Utils.normalizeTextToLowercase(query));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -450,7 +450,7 @@ public abstract class BaseSearchViewController {
|
||||
|
||||
filteredSearchItems.clear();
|
||||
|
||||
String queryLower = Utils.removePunctuationToLowercase(query);
|
||||
String queryLower = Utils.normalizeTextToLowercase(query);
|
||||
Pattern queryPattern = Pattern.compile(Pattern.quote(queryLower), Pattern.CASE_INSENSITIVE);
|
||||
|
||||
// Clear highlighting only for items that were previously visible.
|
||||
|
||||
@@ -54,6 +54,33 @@ public enum ClientType {
|
||||
ANDROID_VR_1_61_48.supportsMultiAudioTracks,
|
||||
"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".
|
||||
* <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a>
|
||||
|
||||
@@ -14,19 +14,11 @@ import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.Utils;
|
||||
import app.revanced.extension.shared.settings.AppLanguage;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofVideoStreamsPatch {
|
||||
|
||||
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain used for internet connectivity verification.
|
||||
* It has an empty response body and is only used to check for a 204 response code.
|
||||
@@ -62,8 +54,7 @@ public class SpoofVideoStreamsPatch {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param language Language override for non-authenticated requests. If this is null then
|
||||
* {@link BaseSettings#SPOOF_VIDEO_STREAMS_LANGUAGE} is used.
|
||||
* @param language Language override for non-authenticated requests.
|
||||
*/
|
||||
public static void setLanguageOverride(@Nullable AppLanguage language) {
|
||||
languageOverride = language;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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.JSONObject;
|
||||
|
||||
@@ -13,7 +11,6 @@ import app.revanced.extension.shared.Logger;
|
||||
import app.revanced.extension.shared.requests.Requester;
|
||||
import app.revanced.extension.shared.requests.Route;
|
||||
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.SpoofVideoStreamsPatch;
|
||||
|
||||
@@ -44,7 +41,7 @@ final class PlayerRoutes {
|
||||
AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride();
|
||||
if (language == null) {
|
||||
// Force original audio has not overrode the language.
|
||||
language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get();
|
||||
language = AppLanguage.DEFAULT;
|
||||
}
|
||||
//noinspection ExtractMethodRecommender
|
||||
Locale streamLocale = language.getLocale();
|
||||
|
||||
@@ -23,6 +23,12 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
||||
public void addPreferences(Context 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,
|
||||
"Enable debug log",
|
||||
"Show extension debug log.",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package app.revanced.twitter.patches.links;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
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.
|
||||
@@ -11,6 +11,16 @@ public final class ChangeLinkSharingDomainPatch {
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -17,15 +17,25 @@ public class ChangeHeaderPatch {
|
||||
DEFAULT(null, null),
|
||||
REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"),
|
||||
PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"),
|
||||
REVANCED("revanced_header_logo", "revanced_header_logo"),
|
||||
REVANCED_MINIMAL("revanced_header_logo_minimal", "revanced_header_logo_minimal"),
|
||||
CUSTOM("custom_header", "custom_header");
|
||||
ROUNDED("revanced_header_rounded"),
|
||||
MINIMAL("revanced_header_minimal"),
|
||||
CUSTOM("revanced_header_custom"),
|
||||
|
||||
// Old enum names for data migration. TODO: Eventually delete these.
|
||||
@Deprecated
|
||||
REVANCED(ROUNDED.attributeName),
|
||||
@Deprecated
|
||||
REVANCED_MINIMAL(MINIMAL.attributeName);
|
||||
|
||||
@Nullable
|
||||
private final String attributeName;
|
||||
@Nullable
|
||||
private final String drawableName;
|
||||
|
||||
HeaderLogo(String attributeName) {
|
||||
this(Objects.requireNonNull(attributeName), Objects.requireNonNull(attributeName));
|
||||
}
|
||||
|
||||
HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) {
|
||||
this.attributeName = attributeName;
|
||||
this.drawableName = drawableName;
|
||||
@@ -42,9 +52,8 @@ public class ChangeHeaderPatch {
|
||||
|
||||
final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
|
||||
if (identifier == 0) {
|
||||
// Identifier is zero if custom header setting was included in imported settings
|
||||
// and a custom image was not included during patching.
|
||||
Logger.printDebug(() -> "Could not find attribute: " + drawableName);
|
||||
// Should never happen.
|
||||
Logger.printException(() -> "Could not find attribute: " + drawableName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
@@ -63,12 +72,14 @@ public class ChangeHeaderPatch {
|
||||
: "_light");
|
||||
|
||||
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
|
||||
if (identifier == 0) {
|
||||
Logger.printDebug(() -> "Could not find drawable: " + drawableFullName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
if (identifier != 0) {
|
||||
return Utils.getContext().getDrawable(identifier);
|
||||
}
|
||||
return Utils.getContext().getDrawable(identifier);
|
||||
|
||||
// Should never happen.
|
||||
Logger.printException(() -> "Could not find drawable: " + drawableFullName);
|
||||
Settings.HEADER_LOGO.resetToDefault();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
private final ByteArrayFilterGroup cellVideoAttribute;
|
||||
|
||||
private final StringFilterGroup aiGeneratedVideoSummarySection;
|
||||
private final StringFilterGroup hypePoints;
|
||||
|
||||
public DescriptionComponentsFilter() {
|
||||
exceptions.addPatterns(
|
||||
@@ -63,6 +64,11 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
"how_this_was_made_section"
|
||||
);
|
||||
|
||||
hypePoints = new StringFilterGroup(
|
||||
Settings.HIDE_HYPE_POINTS,
|
||||
"hype_points_factoid"
|
||||
);
|
||||
|
||||
macroMarkersCarousel = new StringFilterGroup(
|
||||
null,
|
||||
"macro_markers_carousel.e"
|
||||
@@ -96,6 +102,7 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
infoCardsSection,
|
||||
horizontalShelf,
|
||||
howThisWasMadeSection,
|
||||
hypePoints,
|
||||
macroMarkersCarousel,
|
||||
podcastSection,
|
||||
transcriptSection
|
||||
@@ -106,7 +113,7 @@ final class DescriptionComponentsFilter extends Filter {
|
||||
boolean isFiltered(String identifier, String path, byte[] buffer,
|
||||
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
|
||||
|
||||
if (matchedGroup == aiGeneratedVideoSummarySection) {
|
||||
if (matchedGroup == aiGeneratedVideoSummarySection || matchedGroup == hypePoints) {
|
||||
// Only hide if player is open, in case this component is used somewhere else.
|
||||
return PlayerType.getCurrent().isMaximizedOrFullscreen();
|
||||
}
|
||||
|
||||
@@ -87,7 +87,8 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
"post_shelf_slim.e",
|
||||
"videos_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(
|
||||
|
||||
@@ -63,12 +63,12 @@ public class PlayerFlyoutMenuItemsFilter extends Filter {
|
||||
"volume_stable_"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_PLAYER_FLYOUT_HELP,
|
||||
"yt_outline_question_circle_"
|
||||
Settings.HIDE_PLAYER_FLYOUT_LISTEN_WITH_YOUTUBE_MUSIC,
|
||||
"yt_outline_youtube_music_"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_PLAYER_FLYOUT_MORE_INFO,
|
||||
"yt_outline_info_circle_"
|
||||
Settings.HIDE_PLAYER_FLYOUT_HELP,
|
||||
"yt_outline_question_circle_"
|
||||
),
|
||||
new ByteArrayFilterGroup(
|
||||
Settings.HIDE_PLAYER_FLYOUT_LOCK_SCREEN,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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_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_61_48;
|
||||
import static app.revanced.extension.shared.spoof.ClientType.IPADOS;
|
||||
@@ -21,6 +22,11 @@ public class SpoofVideoStreamsPatch {
|
||||
return Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.isAvailable()
|
||||
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ANDROID_VR_1_43_32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Setting<?>> getParentSettings() {
|
||||
return List.of(Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,9 +44,10 @@ public class SpoofVideoStreamsPatch {
|
||||
}
|
||||
|
||||
List<ClientType> availableClients = List.of(
|
||||
VISIONOS,
|
||||
ANDROID_CREATOR,
|
||||
ANDROID_VR_1_43_32,
|
||||
VISIONOS,
|
||||
ANDROID_NO_SDK,
|
||||
IPADOS);
|
||||
|
||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
|
||||
@@ -15,7 +13,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Scanner;
|
||||
|
||||
import app.revanced.extension.shared.Logger;
|
||||
@@ -104,27 +101,6 @@ public final class SeekbarColorPatch {
|
||||
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.
|
||||
*/
|
||||
@@ -135,36 +111,6 @@ public final class SeekbarColorPatch {
|
||||
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.
|
||||
* Modern Lottie style animation.
|
||||
|
||||
@@ -2,7 +2,6 @@ package app.revanced.extension.youtube.settings;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
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.parentsAll;
|
||||
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.MiniplayerHorizontalDragAvailability;
|
||||
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.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
||||
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.Setting;
|
||||
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.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
|
||||
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_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_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_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);
|
||||
@@ -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_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_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_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_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);
|
||||
@@ -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);
|
||||
|
||||
// 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 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_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f, false, false);
|
||||
@@ -475,17 +466,12 @@ public class Settings extends BaseSettings {
|
||||
static {
|
||||
// region Migration
|
||||
|
||||
migrateOldSettingToNew(DEPRECATED_AUTO_REPEAT, LOOP_VIDEO);
|
||||
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS);
|
||||
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER);
|
||||
migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO);
|
||||
migrateOldSettingToNew(DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU, ADVANCED_VIDEO_QUALITY_MENU);
|
||||
migrateOldSettingToNew(DEPRECATED_AUTO_CAPTIONS, DISABLE_AUTO_CAPTIONS);
|
||||
|
||||
// Migrate renamed enum.
|
||||
//noinspection deprecation
|
||||
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {
|
||||
MINIPLAYER_TYPE.save(MINIMAL);
|
||||
// Migrate renamed change header enums.
|
||||
if (HEADER_LOGO.get() == HeaderLogo.REVANCED) {
|
||||
HEADER_LOGO.save(HeaderLogo.ROUNDED);
|
||||
}
|
||||
if (HEADER_LOGO.get() == HeaderLogo.REVANCED_MINIMAL) {
|
||||
HEADER_LOGO.save(HeaderLogo.MINIMAL);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
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,
|
||||
// or is spoofing to a version the same or newer than this app.
|
||||
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
|
||||
// a "revanced_" on the old setting causes duplicate key exceptions during export.
|
||||
SharedPrefCategory revancedPrefs = Setting.preferences;
|
||||
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");
|
||||
Setting.migrateFromOldPreferences(Setting.preferences, RYD_USER_ID, "ryd_user_id");
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,29 +80,34 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
|
||||
Logger.printDebug(() -> "Updating spoof stream side effects preference");
|
||||
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());
|
||||
|
||||
String summary = str("revanced_spoof_video_streams_about_no_audio_tracks");
|
||||
String summary = "";
|
||||
|
||||
switch (clientType) {
|
||||
case ANDROID_CREATOR ->
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
|
||||
summary = str("revanced_spoof_video_streams_about_no_audio_tracks")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
|
||||
// VR 1.61 is not exposed in the UI and should never be reached here.
|
||||
case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 ->
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
|
||||
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 ->
|
||||
summary = str("revanced_spoof_video_streams_about_playback_failure")
|
||||
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
|
||||
case VISIONOS ->
|
||||
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");
|
||||
default -> Logger.printException(() -> "Unknown client: " + clientType);
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (clientType != ClientType.IPADOS) {
|
||||
if (clientType != ClientType.IPADOS && clientType != ClientType.ANDROID_NO_SDK) {
|
||||
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
||||
org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
version = 5.43.0-dev.2
|
||||
version = 5.46.0-dev.4
|
||||
|
||||
@@ -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 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 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 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 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 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_8_05_or_greater ()Z
|
||||
public static final fun is_8_10_or_greater ()Z
|
||||
public static final fun is_8_11_or_greater ()Z
|
||||
public static final fun is_8_15_or_greater ()Z
|
||||
@@ -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 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 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 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 static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,35 @@
|
||||
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.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")
|
||||
val enableDebugMenuPatch = bytecodePatch(
|
||||
name = "Enable debug menu",
|
||||
use = false,
|
||||
use = false
|
||||
) {
|
||||
compatibleWith("com.duolingo"("5.158.4"))
|
||||
compatibleWith("com.duolingo")
|
||||
|
||||
execute {
|
||||
initializeBuildConfigProviderFingerprint.method.apply {
|
||||
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex
|
||||
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
||||
// It seems all categories are allowed on release. Force this on anyway.
|
||||
debugCategoryAllowOnReleaseBuildsFingerprint.method.returnEarly(true)
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"const/4 v$register, 0x1",
|
||||
)
|
||||
// Change build config debug build flag.
|
||||
buildConfigProviderConstructorFingerprint.match(
|
||||
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"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,25 @@ import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
/**
|
||||
* The `BuildConfigProvider` class has two booleans:
|
||||
*
|
||||
* - `isChina`: (usually) compares "play" with "china"...except for builds in China
|
||||
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true`
|
||||
*/
|
||||
|
||||
internal val initializeBuildConfigProviderFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returns("V")
|
||||
opcodes(Opcode.IPUT_BOOLEAN)
|
||||
strings("debug", "release", "china")
|
||||
internal val debugCategoryAllowOnReleaseBuildsFingerprint = fingerprint {
|
||||
returns("Z")
|
||||
parameters()
|
||||
custom { method, classDef ->
|
||||
method.name == "getAllowOnReleaseBuilds" && classDef.type == "Lcom/duolingo/debug/DebugCategory;"
|
||||
}
|
||||
}
|
||||
|
||||
internal val buildConfigProviderConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
parameters()
|
||||
opcodes(Opcode.CONST_4)
|
||||
}
|
||||
|
||||
internal val buildConfigProviderToStringFingerprint = fingerprint {
|
||||
parameters()
|
||||
returns("Ljava/lang/String;")
|
||||
strings("BuildConfigProvider(") // Partial string match.
|
||||
custom { method, _ ->
|
||||
method.name == "toString"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
@@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ val spoofFeaturesPatch = bytecodePatch(
|
||||
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
|
||||
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
|
||||
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
|
||||
"com.google.android.feature.PIXEL_2025_EXPERIENCE",
|
||||
),
|
||||
title = "Features to disable",
|
||||
description = "Google Pixel exclusive features to disable." +
|
||||
|
||||
@@ -3,9 +3,10 @@ package app.revanced.patches.instagram.hide.navigation
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val initializeNavigationButtonsListFingerprint = fingerprint {
|
||||
strings("Nav3")
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Lcom/instagram/common/session/UserSession;", "Z")
|
||||
returns("Ljava/util/List;")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ val enableDeveloperMenuPatch = bytecodePatch(
|
||||
with(clearNotificationReceiverFingerprint.method) {
|
||||
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) {
|
||||
val reference = getReference<MethodReference>()
|
||||
Opcode.INVOKE_STATIC == opcode &&
|
||||
opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
|
||||
reference?.parameterTypes?.size == 1 &&
|
||||
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
|
||||
reference.returnType == "Z"
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
package app.revanced.patches.music.layout.compactheader
|
||||
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.literal
|
||||
|
||||
internal val constructCategoryBarFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
internal val chipCloudFingerprint = fingerprint {
|
||||
returns("V")
|
||||
parameters("Landroid/content/Context;", "L", "L", "L")
|
||||
opcodes(
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
)
|
||||
literal { chipCloud }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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.patch.bytecodePatch
|
||||
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.settings.PreferenceScreen
|
||||
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.util.findFreeRegister
|
||||
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;"
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -33,28 +37,21 @@ val hideCategoryBar = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
chipCloud = resourceMappings["layout", "chip_cloud"]
|
||||
|
||||
addResources("music", "layout.compactheader.hideCategoryBar")
|
||||
|
||||
PreferenceScreen.GENERAL.addPreferences(
|
||||
SwitchPreference("revanced_music_hide_category_bar"),
|
||||
)
|
||||
|
||||
constructCategoryBarFingerprint.method.apply {
|
||||
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
val freeRegister = findFreeRegister(insertIndex, register)
|
||||
chipCloudFingerprint.method.apply {
|
||||
val targetIndex = chipCloudFingerprint.patternMatch!!.endIndex
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex,
|
||||
"""
|
||||
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
|
||||
"""
|
||||
addInstruction(
|
||||
targetIndex + 1,
|
||||
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar(Landroid/view/View;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.settings.PreferenceScreen
|
||||
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_8_11_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(
|
||||
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
|
||||
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
|
||||
fixMediaFetchHotConfig = { true },
|
||||
fixMediaFetchHotConfig = { is_7_16_or_greater },
|
||||
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
|
||||
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
|
||||
|
||||
|
||||
@@ -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.settings.PreferenceScreen
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.patches.music.playservice.is_8_10_or_greater
|
||||
import app.revanced.patches.music.playservice.is_8_05_or_greater
|
||||
import app.revanced.patches.music.playservice.versionCheckPatch
|
||||
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
|
||||
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
block = {
|
||||
@@ -27,8 +24,8 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
)
|
||||
)
|
||||
},
|
||||
fixUseLocalizedAudioTrackFlag = is_8_10_or_greater,
|
||||
fixUseLocalizedAudioTrackFlag = { is_8_05_or_greater },
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
|
||||
subclassExtensionClassDescriptor = "Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;",
|
||||
preferenceScreen = PreferenceScreen.MISC,
|
||||
)
|
||||
|
||||
@@ -4,14 +4,21 @@ package app.revanced.patches.music.playservice
|
||||
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.util.findPlayStoreServicesVersion
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
var is_7_33_or_greater = false
|
||||
// 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_8_10_or_greater = false
|
||||
var is_7_33_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_11_or_greater = false
|
||||
var is_8_05_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_15_or_greater = false
|
||||
var is_8_10_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_11_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_8_15_or_greater: Boolean by Delegates.notNull()
|
||||
private set
|
||||
|
||||
val versionCheckPatch = resourcePatch(
|
||||
@@ -23,8 +30,10 @@ val versionCheckPatch = resourcePatch(
|
||||
val playStoreServicesVersion = findPlayStoreServicesVersion()
|
||||
|
||||
// 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_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_15_or_greater = 251530000 <= playStoreServicesVersion
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>" }
|
||||
}
|
||||
@@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;",
|
||||
),
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -36,13 +36,13 @@ import org.w3c.dom.NodeList
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
|
||||
private val mipmapDirectories = arrayOf(
|
||||
private val mipmapDirectories = mapOf(
|
||||
// Target app does not have ldpi icons.
|
||||
"mipmap-mdpi",
|
||||
"mipmap-hdpi",
|
||||
"mipmap-xhdpi",
|
||||
"mipmap-xxhdpi",
|
||||
"mipmap-xxxhdpi"
|
||||
"mipmap-mdpi" to "108x108 px",
|
||||
"mipmap-hdpi" to "162x162 px",
|
||||
"mipmap-xhdpi" to "216x216 px",
|
||||
"mipmap-xxhdpi" to "324x324 px",
|
||||
"mipmap-xxxhdpi" to "432x432 px"
|
||||
)
|
||||
|
||||
private val iconStyleNames = arrayOf(
|
||||
@@ -104,10 +104,13 @@ internal fun baseCustomBrandingPatch(
|
||||
Folder with images to use as a custom icon.
|
||||
|
||||
The folder must contain one or more of the following folders, depending on the DPI of the device:
|
||||
${mipmapDirectories.joinToString("\n") { "- $it" }}
|
||||
${mipmapDirectories.keys.joinToString("\n") { "- $it" }}
|
||||
|
||||
Each of the folders must contain all of the following files:
|
||||
${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:
|
||||
$USER_CUSTOM_MONOCHROME_FILE_NAME
|
||||
@@ -120,6 +123,7 @@ internal fun baseCustomBrandingPatch(
|
||||
dependsOn(
|
||||
addResourcesPatch,
|
||||
resourceMappingPatch,
|
||||
addBrandLicensePatch,
|
||||
bytecodePatch {
|
||||
execute {
|
||||
mainActivityOnCreateFingerprint.method.addInstruction(
|
||||
@@ -249,7 +253,7 @@ internal fun baseCustomBrandingPatch(
|
||||
)
|
||||
|
||||
// Copy template icon files.
|
||||
mipmapDirectories.forEach { dpi ->
|
||||
mipmapDirectories.keys.forEach { dpi ->
|
||||
copyResources(
|
||||
"custom-branding",
|
||||
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")
|
||||
var copiedFiles = false
|
||||
|
||||
// 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)
|
||||
if (!targetDpiFolder.exists()) return@forEach
|
||||
if (!targetDpiFolder.exists()) {
|
||||
// Should never happen.
|
||||
throw IllegalStateException("Resource not found: $dpiSourceFolder")
|
||||
}
|
||||
|
||||
val customFiles = dpiSourceFolder.listFiles { file ->
|
||||
file.isFile && file.name in USER_CUSTOM_ADAPTIVE_FILE_NAMES
|
||||
}!!
|
||||
|
||||
if (customFiles.size > 0 && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
|
||||
if (customFiles.isNotEmpty() && customFiles.size != USER_CUSTOM_ADAPTIVE_FILE_NAMES.size) {
|
||||
throw PatchException("Must include all required icon files " +
|
||||
"but only found " + customFiles.map { it.name })
|
||||
}
|
||||
@@ -451,8 +456,9 @@ internal fun baseCustomBrandingPatch(
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("Could not find any replacement images in " +
|
||||
"patch option path: " + iconPathFile.absolutePath)
|
||||
throw PatchException("Expected to find directories and files: "
|
||||
+ USER_CUSTOM_ADAPTIVE_FILE_NAMES.contentToString()
|
||||
+ "\nBut none were found in the provided option file path: " + iconPathFile.absolutePath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package app.revanced.patches.shared.misc.audio
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.util.containsLiteralInstruction
|
||||
import app.revanced.util.literal
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val formatStreamModelToStringFingerprint = fingerprint {
|
||||
@@ -20,11 +20,7 @@ internal val formatStreamModelToStringFingerprint = fingerprint {
|
||||
internal const val AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG = 45666189L
|
||||
|
||||
internal val selectAudioStreamFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returns("L")
|
||||
custom { method, _ ->
|
||||
method.parameters.size > 2 // Method has a large number of parameters and may change.
|
||||
&& method.containsLiteralInstruction(AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG)
|
||||
literal {
|
||||
AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
internal fun forceOriginalAudioPatch(
|
||||
block: BytecodePatchBuilder.() -> Unit = {},
|
||||
executeBlock: BytecodePatchContext.() -> Unit = {},
|
||||
fixUseLocalizedAudioTrackFlag: Boolean,
|
||||
fixUseLocalizedAudioTrackFlag: BytecodePatchContext.() -> Boolean,
|
||||
mainActivityOnCreateFingerprint: Fingerprint,
|
||||
subclassExtensionClassDescriptor: String,
|
||||
preferenceScreen: BasePreferenceScreen.Screen
|
||||
@@ -64,7 +64,7 @@ internal fun forceOriginalAudioPatch(
|
||||
|
||||
// Disable feature flag that ignores the default track flag
|
||||
// and instead overrides to the user region language.
|
||||
if (fixUseLocalizedAudioTrackFlag) {
|
||||
if (fixUseLocalizedAudioTrackFlag()) {
|
||||
selectAudioStreamFingerprint.method.insertLiteralOverride(
|
||||
AUDIO_STREAM_IGNORE_DEFAULT_FEATURE_FLAG,
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->ignoreDefaultAudioStream(Z)Z"
|
||||
|
||||
@@ -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.addResources
|
||||
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.IntentPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
|
||||
@@ -61,7 +62,11 @@ fun settingsPatch (
|
||||
rootPreferences: List<Pair<BasePreference, String>>? = null,
|
||||
preferences: Set<BasePreference>,
|
||||
) = resourcePatch {
|
||||
dependsOn(addResourcesPatch, settingsColorPatch)
|
||||
dependsOn(
|
||||
addResourcesPatch,
|
||||
settingsColorPatch,
|
||||
addBrandLicensePatch
|
||||
)
|
||||
|
||||
execute {
|
||||
copyResources(
|
||||
|
||||
@@ -47,11 +47,15 @@ val changeLyricsProviderPatch = bytecodePatch(
|
||||
// may not allow network connections or the network may be down.
|
||||
try {
|
||||
InetAddress.getByName(host)
|
||||
} catch (e: UnknownHostException) {
|
||||
} catch (_: UnknownHostException) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"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
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,20 @@ package app.revanced.patches.tiktok.interaction.downloads
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import app.revanced.util.returnEarly
|
||||
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")
|
||||
val downloadsPatch = bytecodePatch(
|
||||
@@ -28,60 +34,45 @@ val downloadsPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
aclCommonShareFingerprint.method.replaceInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x0
|
||||
return v0
|
||||
""",
|
||||
)
|
||||
|
||||
aclCommonShare2Fingerprint.method.replaceInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x2
|
||||
return v0
|
||||
""",
|
||||
)
|
||||
aclCommonShareFingerprint.method.returnEarly(0)
|
||||
aclCommonShare2Fingerprint.method.returnEarly(2)
|
||||
|
||||
// Download videos without watermark.
|
||||
aclCommonShare3Fingerprint.method.addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, Lapp/revanced/extension/tiktok/download/DownloadsPatch;->shouldRemoveWatermark()Z
|
||||
move-result v0
|
||||
if-eqz v0, :noremovewatermark
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
:noremovewatermark
|
||||
nop
|
||||
""",
|
||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldRemoveWatermark()Z
|
||||
move-result v0
|
||||
if-eqz v0, :noremovewatermark
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
:noremovewatermark
|
||||
nop
|
||||
""",
|
||||
)
|
||||
|
||||
// Change the download path patch.
|
||||
downloadUriFingerprint.method.apply {
|
||||
val firstIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.name == "<init>"
|
||||
}
|
||||
val secondIndex = indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.returnType?.contains("Uri") == true
|
||||
}
|
||||
findInstructionIndicesReversedOrThrow {
|
||||
getReference<FieldReference>().let {
|
||||
it?.definingClass == "Landroid/os/Environment;" && it.name.startsWith("DIRECTORY_")
|
||||
}
|
||||
}.forEach { fieldIndex ->
|
||||
val pathRegister = getInstruction<OneRegisterInstruction>(fieldIndex).registerA
|
||||
val builderRegister = getInstruction<FiveRegisterInstruction>(fieldIndex + 1).registerC
|
||||
|
||||
addInstructions(
|
||||
secondIndex,
|
||||
"""
|
||||
invoke-static {}, Lapp/revanced/extension/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String;
|
||||
move-result-object v0
|
||||
""",
|
||||
)
|
||||
// Remove 'field load → append → "/Camera/" → append' block.
|
||||
removeInstructions(fieldIndex, 4)
|
||||
|
||||
addInstructions(
|
||||
firstIndex,
|
||||
"""
|
||||
invoke-static {}, Lapp/revanced/extension/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String;
|
||||
move-result-object v0
|
||||
""",
|
||||
)
|
||||
addInstructions(
|
||||
fieldIndex,
|
||||
"""
|
||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->getDownloadPath()Ljava/lang/String;
|
||||
move-result-object v$pathRegister
|
||||
invoke-virtual { v$builderRegister, v$pathRegister }, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
settingsStatusLoadFingerprint.method.addInstruction(
|
||||
|
||||
@@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.layout.branding.addBrandLicensePatch
|
||||
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
|
||||
@@ -18,7 +19,7 @@ val settingsPatch = bytecodePatch(
|
||||
name = "Settings",
|
||||
description = "Adds ReVanced settings to TikTok.",
|
||||
) {
|
||||
dependsOn(sharedExtensionPatch)
|
||||
dependsOn(sharedExtensionPatch, addBrandLicensePatch)
|
||||
|
||||
compatibleWith(
|
||||
"com.ss.android.ugc.trill"("36.5.4"),
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,26 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
|
||||
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
|
||||
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
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.UnknownHostException
|
||||
import java.util.logging.Logger
|
||||
|
||||
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/links/ChangeLinkSharingDomainPatch;"
|
||||
|
||||
internal val domainNameOption by stringOption(
|
||||
internal val domainNameOption = stringOption(
|
||||
key = "domainName",
|
||||
default = "https://fxtwitter.com",
|
||||
default = "fxtwitter.com",
|
||||
title = "Domain name",
|
||||
description = "The domain name to use when sharing links.",
|
||||
required = true,
|
||||
@@ -28,23 +31,25 @@ internal val domainNameOption by stringOption(
|
||||
// may not allow network connections or the network may be down.
|
||||
try {
|
||||
InetAddress.getByName(it)
|
||||
} catch (e: UnknownHostException) {
|
||||
} catch (_: UnknownHostException) {
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"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
|
||||
}
|
||||
|
||||
// TODO restore this once Manager uses a fixed version of Patcher
|
||||
/*
|
||||
internal val changeLinkSharingDomainResourcePatch = resourcePatch {
|
||||
execute {
|
||||
val domainName = domainNameOption!!
|
||||
val domainName = domainNameOption.value!!
|
||||
|
||||
val shareLinkTemplate = if (domainName.endsWith("/")) {
|
||||
"$domainName%1\$s/status/%2\$s"
|
||||
} else {
|
||||
"$domainName/%1\$s/status/%2\$s"
|
||||
}
|
||||
val shareLinkTemplate = "https://$domainName/%1\$s/status/%2\$s"
|
||||
|
||||
document("res/values/strings.xml").use { document ->
|
||||
document.documentElement.childNodes.findElementByAttributeValueOrThrow(
|
||||
@@ -54,14 +59,15 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@Suppress("unused")
|
||||
val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
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(
|
||||
changeLinkSharingDomainResourcePatch,
|
||||
sharedExtensionPatch,
|
||||
)
|
||||
|
||||
@@ -72,11 +78,11 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
)
|
||||
)
|
||||
|
||||
execute {
|
||||
val domainName = domainNameOption!!
|
||||
val domainName by domainNameOption()
|
||||
|
||||
execute {
|
||||
// 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.
|
||||
linkBuilderFingerprint.method.addInstructions(
|
||||
@@ -87,5 +93,22 @@ val changeLinkSharingDomainPatch = bytecodePatch(
|
||||
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;",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.twitter.misc.links
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val openLinkFingerprint = fingerprint {
|
||||
returns("V")
|
||||
@@ -17,6 +18,18 @@ internal val linkBuilderFingerprint = fingerprint {
|
||||
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 {
|
||||
custom { method, classDef ->
|
||||
method.name == "getShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
|
||||
|
||||
@@ -9,6 +9,7 @@ import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patcher.util.Document
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
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.resourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
||||
@@ -24,15 +25,43 @@ import java.io.File
|
||||
|
||||
private val variants = arrayOf("light", "dark")
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/ChangeHeaderPatch;"
|
||||
private val targetResourceDirectoryNames = mapOf(
|
||||
"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 {
|
||||
dependsOn(resourceMappingPatch)
|
||||
dependsOn(
|
||||
resourceMappingPatch,
|
||||
addBrandLicensePatch
|
||||
)
|
||||
|
||||
execute {
|
||||
// Resources are not used during patching, but extension code uses these
|
||||
// images so verify they exist.
|
||||
// Verify images exist. Resources are not used during patching but extension code does.
|
||||
arrayOf(
|
||||
"yt_ringo2_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")
|
||||
val changeHeaderPatch = resourcePatch(
|
||||
name = "Change header",
|
||||
@@ -110,7 +117,7 @@ val changeHeaderPatch = resourcePatch(
|
||||
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
|
||||
|
||||
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:
|
||||
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
|
||||
@@ -120,67 +127,41 @@ val changeHeaderPatch = resourcePatch(
|
||||
execute {
|
||||
addResources("youtube", "layout.branding.changeHeaderPatch")
|
||||
|
||||
fun getLightDarkFileNames(vararg resourceNames: String): Array<String> =
|
||||
variants.flatMap { variant ->
|
||||
resourceNames.map { resource -> "${resource}_$variant.png" }
|
||||
}.toTypedArray()
|
||||
|
||||
val logoResourceFileNames = getLightDarkFileNames(*logoResourceNames)
|
||||
copyResources(
|
||||
"change-header",
|
||||
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
|
||||
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
if (custom == null) {
|
||||
ListPreference("revanced_header_logo")
|
||||
} else {
|
||||
ListPreference(
|
||||
key = "revanced_header_logo",
|
||||
entriesKey = "revanced_header_logo_custom_entries",
|
||||
entryValuesKey = "revanced_header_logo_custom_entry_values"
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException("The custom icon path must be a folder: "
|
||||
+ customFile.absolutePath)
|
||||
logoResourceNames.forEach { logo ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
"drawable",
|
||||
logo + "_" + variant + ".xml"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val sourceFolders = customFile.listFiles { file -> file.isDirectory }
|
||||
?: throw PatchException("The custom icon path contains no subfolders: " +
|
||||
customFile.absolutePath)
|
||||
|
||||
val customResourceFileNames = getLightDarkFileNames(CUSTOM_HEADER_RESOURCE_NAME)
|
||||
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
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)
|
||||
// Copy custom template. Images are only used if settings
|
||||
// are imported and a custom header is enabled.
|
||||
targetResourceDirectoryNames.keys.forEach { dpi ->
|
||||
variants.forEach { variant ->
|
||||
copyResources(
|
||||
"change-header",
|
||||
ResourceGroup(
|
||||
dpi,
|
||||
*customHeaderResourceFileNames
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,9 +180,7 @@ val changeHeaderPatch = resourcePatch(
|
||||
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.
|
||||
@@ -227,22 +206,58 @@ val changeHeaderPatch = resourcePatch(
|
||||
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(
|
||||
if (custom == null) {
|
||||
ListPreference("revanced_header_logo")
|
||||
} else {
|
||||
ListPreference(
|
||||
key = "revanced_header_logo",
|
||||
entriesKey = "revanced_header_logo_custom_entries",
|
||||
entryValuesKey = "revanced_header_logo_custom_entry_values"
|
||||
// Copy user provided images last, so if an exception is thrown due to bad input.
|
||||
if (custom != null) {
|
||||
val customFile = File(custom!!.trim())
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException("The custom header path cannot be found: " +
|
||||
customFile.absolutePath
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
||||
SwitchPreference("revanced_hide_chapters_section"),
|
||||
SwitchPreference("revanced_hide_info_cards_section"),
|
||||
SwitchPreference("revanced_hide_how_this_was_made_section"),
|
||||
SwitchPreference("revanced_hide_hype_points"),
|
||||
SwitchPreference("revanced_hide_key_concepts_section"),
|
||||
SwitchPreference("revanced_hide_podcast_section"),
|
||||
SwitchPreference("revanced_hide_transcript_section"),
|
||||
|
||||
@@ -45,10 +45,10 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
|
||||
SwitchPreference("revanced_hide_player_flyout_loop_video"),
|
||||
SwitchPreference("revanced_hide_player_flyout_ambient_mode"),
|
||||
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_speed"),
|
||||
SwitchPreference("revanced_hide_player_flyout_lock_screen"),
|
||||
SwitchPreference("revanced_hide_player_flyout_more_info"),
|
||||
SwitchPreference(
|
||||
key = "revanced_hide_player_flyout_audio_track",
|
||||
tag = "app.revanced.extension.youtube.settings.preference.HideAudioFlyoutMenuPreference"
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package app.revanced.patches.youtube.layout.seekbar
|
||||
|
||||
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.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
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.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_46_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.settings.settingsPatch
|
||||
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.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.inputStreamFromBundledResource
|
||||
import app.revanced.util.insertLiteralOverride
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
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.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import org.w3c.dom.Element
|
||||
import java.io.ByteArrayInputStream
|
||||
import kotlin.use
|
||||
|
||||
internal var reelTimeBarPlayedColorId = -1L
|
||||
private set
|
||||
@@ -57,8 +48,6 @@ internal var ytTextSecondaryId = -1L
|
||||
internal var inlineTimeBarLiveSeekableRangeId = -1L
|
||||
private set
|
||||
|
||||
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
|
||||
|
||||
private val seekbarColorResourcePatch = resourcePatch {
|
||||
dependsOn(
|
||||
settingsPatch,
|
||||
@@ -92,21 +81,6 @@ private val seekbarColorResourcePatch = resourcePatch {
|
||||
"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[
|
||||
"color",
|
||||
"yt_youtube_magenta",
|
||||
@@ -115,99 +89,9 @@ private val seekbarColorResourcePatch = resourcePatch {
|
||||
"attr",
|
||||
"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;"
|
||||
|
||||
val seekbarColorPatch = bytecodePatch(
|
||||
@@ -344,21 +228,6 @@ val seekbarColorPatch = bytecodePatch(
|
||||
|
||||
// Hook the splash animation to set the a seekbar color.
|
||||
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
|
||||
|
||||
findInstructionIndicesReversedOrThrow {
|
||||
@@ -371,13 +240,11 @@ val seekbarColorPatch = bytecodePatch(
|
||||
replaceInstruction(
|
||||
index,
|
||||
"invoke-static { v${instruction.registerC}, v${instruction.registerD} }, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie" +
|
||||
"(Lcom/airbnb/lottie/LottieAnimationView;I)V"
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->setSplashAnimationLottie(Lcom/airbnb/lottie/LottieAnimationView;I)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add non obfuscated method aliases for `setAnimation(int)`
|
||||
// and `setAnimation(InputStream, String)` so extension code can call them.
|
||||
lottieAnimationViewSetAnimationIntFingerprint.classDef.methods.apply {
|
||||
|
||||
@@ -4,72 +4,75 @@ package app.revanced.patches.youtube.misc.playservice
|
||||
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.util.findPlayStoreServicesVersion
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
// Use notNull delegate so an exception is thrown if these fields are accessed before they are set.
|
||||
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_03_or_greater = false
|
||||
var is_19_03_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_04_or_greater = false
|
||||
var is_19_04_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_16_or_greater = false
|
||||
var is_19_16_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_17_or_greater = false
|
||||
var is_19_17_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_18_or_greater = false
|
||||
var is_19_18_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_23_or_greater = false
|
||||
var is_19_23_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_25_or_greater = false
|
||||
var is_19_25_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_26_or_greater = false
|
||||
var is_19_26_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_29_or_greater = false
|
||||
var is_19_29_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_32_or_greater = false
|
||||
var is_19_32_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_33_or_greater = false
|
||||
var is_19_33_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
@Deprecated("19.34.42 is the lowest supported version")
|
||||
var is_19_34_or_greater = false
|
||||
var is_19_34_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_35_or_greater = false
|
||||
var is_19_35_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_36_or_greater = false
|
||||
var is_19_36_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_41_or_greater = false
|
||||
var is_19_41_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_43_or_greater = false
|
||||
var is_19_43_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_46_or_greater = false
|
||||
var is_19_46_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_47_or_greater = false
|
||||
var is_19_47_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_19_49_or_greater = false
|
||||
var is_19_49_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_02_or_greater = false
|
||||
var is_20_02_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_03_or_greater = false
|
||||
var is_20_03_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_05_or_greater = false
|
||||
var is_20_05_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_07_or_greater = false
|
||||
var is_20_07_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_09_or_greater = false
|
||||
var is_20_09_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_10_or_greater = false
|
||||
var is_20_10_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_14_or_greater = false
|
||||
var is_20_14_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
var is_20_15_or_greater = false
|
||||
var is_20_15_or_greater : Boolean by Delegates.notNull()
|
||||
private set
|
||||
|
||||
val versionCheckPatch = resourcePatch(
|
||||
|
||||
@@ -63,13 +63,6 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
|
||||
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
|
||||
),
|
||||
SwitchPreference("revanced_spoof_video_streams_av1"),
|
||||
ListPreference(
|
||||
key = "revanced_spoof_video_streams_language",
|
||||
// Language strings are declared in Setting patch.
|
||||
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"),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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.shared.mainActivityOnCreateFingerprint
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
block = {
|
||||
@@ -29,8 +26,8 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
|
||||
)
|
||||
)
|
||||
},
|
||||
fixUseLocalizedAudioTrackFlag = is_20_07_or_greater,
|
||||
fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater },
|
||||
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
|
||||
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
|
||||
subclassExtensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;",
|
||||
preferenceScreen = PreferenceScreen.VIDEO,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">إخفاء \'كيف تم إنشاء هذا المحتوى\'</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">تم إخفاء قسم كيف تم إنشاء هذا المحتوى</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">يتم عرض قسم كيف تم إنشاء هذا المحتوى</string>
|
||||
<string name="revanced_hide_hype_points_title">إخفاء نقاط التشجيع</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">تم إخفاء نقاط التشجيع</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">يتم عرض نقاط التشجيع</string>
|
||||
<string name="revanced_hide_podcast_section_title">إخفاء \'استكشاف البودكاست\'</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">تم إخفاء قسم استكشاف البودكاست</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">يتم عرض قسم استكشاف البودكاست</string>
|
||||
@@ -771,15 +774,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_player_flyout_speed_title">إخفاء سرعة التشغيل</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">تم إخفاء قائمة سرعة التشغيل</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">يتم عرض قائمة سرعة التشغيل</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">إخفاء المزيد من المعلومات</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">تم إخفاء قائمة المزيد من المعلومات</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">يتم عرض قائمة المزيد من المعلومات</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">إخفاء شاشة القفل</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">تم إخفاء قائمة شاشة القفل</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">يتم عرض قائمة شاشة القفل</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">إخفاء الاستماع مع YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">تم إخفاء قائمة الاستماع مع YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">يتم عرض قائمة الاستماع مع YouTube Music</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">إخفاء المقطع الصوتي</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">تم إخفاء قائمة المقطع الصوتي</string>
|
||||
@@ -1639,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_summary_on">يتم عرض نوع العميل في إحصاءات تقنية</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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -135,9 +135,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -259,7 +258,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -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_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_compact_banner_title">Yığcam etiketləri gizlət</string>
|
||||
<string name="revanced_hide_compact_banner_summary_on">Yığcam etiketlər gizlidir</string>
|
||||
<string name="revanced_hide_compact_banner_summary_off">Yığcam etiketlər göstərilir</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 afişalar gizlidir</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_summary_on">İanə qutusu gizlidir</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_off">İanə qutusu göstərilir</string>
|
||||
@@ -328,6 +328,9 @@ Hər halda, bunu aktivləşdirmə IP ünvanınız kimi bəzi istifadəçi məlum
|
||||
<string name="revanced_hide_how_this_was_made_section_title">\'Bu kontent necə hazırlanıb\'ı Gizlət</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Bu məzmunun necə hazırlandığı bölməsi gizlidir</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Bu məzmunun necə hazırlandığı bölməsi görünür</string>
|
||||
<string name="revanced_hide_hype_points_title">Hype nöqtələrini gizlət</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype nöqtələri gizlədilib</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype nöqtələri göstərilir</string>
|
||||
<string name="revanced_hide_podcast_section_title">\'Podkastı araşdırın\"-ı Gizlət</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Podkast bölməsin araşdırın gizlidir</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Podkast bölməsin araşdırın görünür</string>
|
||||
@@ -471,9 +474,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_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_end_screen_store_banner_title">Son ekran mağaza etiketini 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_off">Son ekran alış-veriş etiketi görünür</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 mağaza afişası gizlidir</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_summary_on">"Tam ekran reklamları gizlidir
|
||||
|
||||
@@ -484,9 +487,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_summary_on">Ümumi reklamlar gizlidir</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_summary_on">Məhsul etiketləri 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_title">Məhsul afişaların gizlət</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 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_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>
|
||||
@@ -496,7 +499,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_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_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_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>
|
||||
@@ -771,15 +774,14 @@ Bu seçimi dəyişdirmə işə düşmürsə, Gizli rejimə keçməyə çalışı
|
||||
<string name="revanced_hide_player_flyout_speed_title">\"Oynatma sürəti\"ni gizlət</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Oynatma sürəti menyusu gizlidir</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Oynatma sürəti menyusu göstərilir</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">\"Daha çox məlumat\"ı gizlət</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Ətraflı məlumat menyusu gizlidir</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Ətraflı məlumat menyusu göstərilir</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Kilid ekranını gizlət</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Kilid ekranı menyusu gizlidir</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Kilid ekranı menyusu göstərilir</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">YouTube Music ilə dinləməni gizlət</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">YouTube Music ilə dinlə menyusu gizlədilib</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">YouTube Music ilə dinlə menyusu göstərilir</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Səs trekini gizlət</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Səs axını menyusu gizlidir</string>
|
||||
@@ -1638,10 +1640,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Схаваць «Як быў створаны гэты кантэнт»</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Раздзел «Як быў створаны гэты кантэнт» схаваны</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Раздзел «Як быў створаны гэты кантэнт» паказаны</string>
|
||||
<string name="revanced_hide_hype_points_title">Схаваць Hype балы</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype балы схаваны</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype балы паказаны</string>
|
||||
<string name="revanced_hide_podcast_section_title">Схаваць «Пазнаёмцеся з падкастам»</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Раздзел «Пазнаёмцеся з падкастам» схаваны</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Раздзел «Пазнаёмцеся з падкастам» паказаны</string>
|
||||
@@ -771,15 +774,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_player_flyout_speed_title">Схаваць хуткасць прайгравання</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Меню хуткасці прайгравання схавана</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Адлюструецца меню хуткасці прайгравання</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Схаваць Дадатковая інфармацыя</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Меню дадатковай інфармацыі схавана</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Паказана меню дадатковай інфармацыі</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Схаваць экран блакіроўкі</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Меню экрана блакіроўкі схавана</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Адлюстроўваецца меню блакіроўкі экрана</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Схаваць \'Слухаць у YouTube Music\'</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Меню \'Слухаць у YouTube Music\' схавана</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Меню \'Слухаць у YouTube Music\' паказана</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Схаваць гукавую дарожку</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Меню гукавой дарожкі схавана</string>
|
||||
@@ -1640,10 +1642,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_summary_on">Тып кліента адлюстроўваецца ў статыстыцы для спецыялістаў</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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Скриване на \"Как е създадено това съдържание\"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Секцията \"Как е създадено това съдържание\" е скрита</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Секцията \"Как е създадено това съдържание\" е показана</string>
|
||||
<string name="revanced_hide_hype_points_title">Скриване на точките на хайп</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Точките на хайп са скрити</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Точките на хайп са показани</string>
|
||||
<string name="revanced_hide_podcast_section_title">Скриване на \"Разгледайте подкаста\"</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Секцията \"Разгледайте подкаста\" е скрита</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Секцията \"Разгледайте подкаста\" е показана</string>
|
||||
@@ -771,15 +774,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_player_flyout_speed_title">Скриване на скоростта на възпроизвеждане</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Менюто за скорост на видеото е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Менюто за скорост на видеото се показва</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">\"Допълнителна информация\"</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">\"Допълнителна информация\" е скрита</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">\"Допълнителна информация\" се показва</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">\"Заключен екран\"</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Менюто на заключен екран е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Менюто на заключен екран се показва</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Скриване на Слушане с YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Менюто Слушане с YouTube Music е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Менюто Слушане с YouTube Music е показано</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Избор на Аудио</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Менюто за избор на Аудио е скрито</string>
|
||||
@@ -1639,10 +1641,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -324,6 +324,9 @@ MicroG-এর জন্য ব্যাটারি অপ্টিমাইজ
|
||||
<string name="revanced_hide_how_this_was_made_section_title">\'How this content was made\' লুকান</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">How this content was made বিভাগটি লুকানো আছে</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">How this content was made বিভাগটি দেখানো হয়েছে</string>
|
||||
<string name="revanced_hide_hype_points_title">হাইপ পয়েন্ট লুকান</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">হাইপ পয়েন্ট লুকানো আছে</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">হাইপ পয়েন্ট দেখানো আছে</string>
|
||||
<string name="revanced_hide_podcast_section_title">\'Explore the podcast\' লুকান</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Explore the podcast বিভাগটি লুকানো আছে</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Explore the podcast বিভাগটি দেখানো হয়েছে</string>
|
||||
@@ -767,15 +770,14 @@ MicroG-এর জন্য ব্যাটারি অপ্টিমাইজ
|
||||
<string name="revanced_hide_player_flyout_speed_title">প্লেব্যাকের স্পিড লুকান</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">প্লেব্যাকের স্পিড মেনু লুকিয়ে রয়েছে</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">প্লেব্যাকের স্পিড মেনু প্রদর্শিত হয়েছে</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">আরো তথ্য লুকান</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">আরও তথ্য মেনু লুকানো আছে</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">আরও তথ্য মেনু দেখানো হয়</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">লক স্ক্রীন লুকান</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">লক স্ক্রীন মেনু লুকানো আছে</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">লক স্ক্রিন মেনু দেখানো হয়েছে</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">ইউটিউব মিউজিক দিয়ে শুনুন লুকান</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">ইউটিউব মিউজিক দিয়ে শুনুন মেনু লুকানো আছে</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">ইউটিউব মিউজিক দিয়ে শুনুন মেনু দেখানো আছে</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">অডিও ট্র্যাক লুকান</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">অডিও ট্র্যাক মেনু লুকানো আছে</string>
|
||||
@@ -1635,10 +1637,6 @@ AV1 সহ ভিডিও প্লেব্যাক আটকে যেতে
|
||||
<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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Pokud se Doodle v současné době zobrazuje ve vaší oblasti a toto nastavení
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Skrýt „Jak tento obsah vznikl“</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Sekce Jak tento obsah vznikl je skrytá</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Sekce Jak tento obsah vznikl je zobrazena</string>
|
||||
<string name="revanced_hide_hype_points_title">Skrýt Hype body</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype body jsou skryté</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype body jsou zobrazené</string>
|
||||
<string name="revanced_hide_podcast_section_title">Skrýt „Prozkoumat podcast“</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Sekce Prozkoumat podcast je skrytá</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Sekce Prozkoumat podcast je zobrazena</string>
|
||||
@@ -771,15 +774,14 @@ Pokud změna tohoto nastavení nemá žádný účinek, zkuste přepnout do rež
|
||||
<string name="revanced_hide_player_flyout_speed_title">Skrýt Rychlost přehrávání</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Menu Rychlost přehrávání je skryto</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Menu Rychlost přehrávání je zobrazeno</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Skrýt Více informací</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Menu Více informací je skryto</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Menu Více informací je zobrazeno</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Skrýt Zamknout obrazovku</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Menu Zamknout obrazovku je skryto</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Menu Zamknout obrazovku je zobrazeno</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Skrýt Poslouchat v YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Nabídka Poslouchat v YouTube Music je skrytá</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Nabídka Poslouchat v YouTube Music je zobrazena</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Skrýt Zvuková stopa</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Menu Zvuková stopa je skryto</string>
|
||||
@@ -1639,10 +1641,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Hvis et Doodle vises i øjeblikket i din region, og denne skjuleindstilling er a
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Skjul \"Hvordan dette indhold blev lavet\"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Sektionen Sådan blev dette indhold lavet er skjult</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Sektionen Sådan blev dette indhold lavet vises</string>
|
||||
<string name="revanced_hide_hype_points_title">Skjul Hype-point</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype-point er skjult</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype-point er vist</string>
|
||||
<string name="revanced_hide_podcast_section_title">Skjul \"Udforsk podcasten\"</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Sektionen Udforsk podcasten er skjult</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Sektionen Udforsk podcasten vises</string>
|
||||
@@ -771,15 +774,14 @@ Hvis ændring af denne indstilling ikke træder i kraft, kan du prøve at skifte
|
||||
<string name="revanced_hide_player_flyout_speed_title">Skjul afspilningshastighed</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Afspilningshastighedsmenu er skjult</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Afspilningshastighed menuen vises</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Skjul Mere info</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Mere info menu er skjult</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Mere info menu er vist</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Skjul låseskærm</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Menuen Låseskærm er skjult</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Låseskærmsmenuen vises</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Skjul Lyt med YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Lyt med YouTube Music-menuen er skjult</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Lyt med YouTube Music-menuen vises</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Skjul lydspor</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Menuen for lydspor er skjult</string>
|
||||
@@ -1641,10 +1643,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -327,6 +327,9 @@ Wenn ein Doodle zurzeit in Ihrer Region angezeigt wird und diese Einstellung zum
|
||||
<string name="revanced_hide_how_this_was_made_section_title">\"Wie dieser Inhalt erstellt wurde\" ausblenden</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Der Abschnitt \"Wie dieser Inhalt erstellt wurde\" ist ausgeblendet</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Der Abschnitt \"Wie dieser Inhalt erstellt wurde\" wird angezeigt</string>
|
||||
<string name="revanced_hide_hype_points_title">Hype-Punkte ausblenden</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype-Punkte sind ausgeblendet</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype-Punkte werden angezeigt</string>
|
||||
<string name="revanced_hide_podcast_section_title">\'Podcast entdecken\' ausblenden</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Der Abschnitt \"Podcast entdecken\" ist ausgeblendet</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Der Abschnitt \"Podcast entdecken\" wird angezeigt</string>
|
||||
@@ -768,15 +771,14 @@ Wenn diese Änderung nicht wirksam wird, versuchen Sie, in den Inkognito-Modus z
|
||||
<string name="revanced_hide_player_flyout_speed_title">Wiedergabegeschwindigkeit ausblenden</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Wiedergabegeschwindigkeit ist ausgeblendet</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Wiedergabegeschwindigkeit wird angezeigt</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Mehr Info ausblenden</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Mehr Info-Menü ist ausgeblendet</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Mehr Info-Menü wird angezeigt</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Sperrbildschirm ausblenden</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Sperrbildschirm-Menü ist ausgeblendet</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Sperrbildschirm-Menü wird angezeigt</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">„Mit YouTube Music hören“ ausblenden</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">„Mit YouTube Music hören“-Menü ist ausgeblendet</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">„Mit YouTube Music hören“-Menü wird angezeigt</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Audiospur ausblenden</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Audiospur-Menü ist ausgeblendet</string>
|
||||
@@ -1636,10 +1638,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -330,6 +330,9 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Ενότητα «Πως δημιουργήθηκε αυτό το περιεχόμενο»</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Εμφανίζεται</string>
|
||||
<string name="revanced_hide_hype_points_title">Πόντοι Hype</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Κρυμμένοι</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Εμφανίζονται</string>
|
||||
<string name="revanced_hide_podcast_section_title">Ενότητα «Εξερευνήστε το podcast»</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Κρυμμένη</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Εμφανίζεται</string>
|
||||
@@ -773,15 +776,14 @@ Second \"item\" text"</string>
|
||||
<string name="revanced_hide_player_flyout_speed_title">Μενού «Ταχύτητα αναπαραγωγής»</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Εμφανίζεται</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Μενού «Περισσότερα»</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Εμφανίζεται</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Μενού «Οθόνη κλειδώματος»</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Εμφανίζεται</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Μενού «Ακρόαση με YouTube Music»</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Κρυμμένο</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Εμφανίζεται</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Μενού «Κομμάτι ήχου»</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Κρυμμένο</string>
|
||||
@@ -1638,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_summary_on">Το πρόγραμμα πελάτη εμφανίζεται στο μενού «Στατιστικά για σπασίκλες»</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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Si un doodle se está mostrando actualmente en tu región y este ajuste de ocult
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Ocultar \"Cómo se hizo este contenido\"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">La sección Cómo se hizo este contenido está oculta</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Se muestra la sección Cómo se hizo este contenido</string>
|
||||
<string name="revanced_hide_hype_points_title">Ocultar puntos de Hype</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Los puntos de Hype están ocultos</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Los puntos de Hype están visibles</string>
|
||||
<string name="revanced_hide_podcast_section_title">Ocultar \"Explora el pódcast\"</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">La sección Explora el pódcast está oculta</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Se muestra la sección Explora el pódcast</string>
|
||||
@@ -771,15 +774,14 @@ Si cambiar este ajuste no tiene efecto, intenta cambiar al modo incógnito."</st
|
||||
<string name="revanced_hide_player_flyout_speed_title">Ocultar velocidad de reproducción</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Menú de velocidad de reproducción oculto</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Mostrar menú de velocidad de reproducción</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Ocultar Más información</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">El menú Más información está oculto</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Se muestra el menú Más información</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Ocultar pantalla de bloqueo</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">El menú de la pantalla de bloqueo está oculto</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Se muestra el menú de pantalla de bloqueo</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Ocultar Escuchar con YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">El menú Escuchar con YouTube Music está oculto</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">El menú Escuchar con YouTube Music está visible</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Ocultar pista de audio</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">El menú de pista de audio está oculto</string>
|
||||
@@ -1628,10 +1630,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Kui Doodle on teie piirkonnas praegu nähtav ja see peitmise seade on sisse lül
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Peida \"Kuidas see sisu loodi\"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Kuidas see sisu loodi jaotis on peidetud</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Kuidas see sisu loodi jaotis on kuvatud</string>
|
||||
<string name="revanced_hide_hype_points_title">Peida Hype\'i punktid</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype\'i punktid on peidetud</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype\'i punktid on nähtavad</string>
|
||||
<string name="revanced_hide_podcast_section_title">Peida \"Avasta taskuhäälingut\"</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Avasta taskuhäälingut jaotis on peidetud</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Avasta taskuhäälingut jaotis on kuvatud</string>
|
||||
@@ -771,15 +774,14 @@ Kui selle sätte muutmine ei avalda mõju, proovige lülituda Inkognito režiimi
|
||||
<string name="revanced_hide_player_flyout_speed_title">Peida Esituse kiirus</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Esituse kiiruse menüü on peidetud</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Esituse kiiruse menüü on nähtav</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Peida Lisateave</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Lisateabe menüü on peidetud</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Lisateabe menüü on nähtav</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Peida Ekraani lukustus</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Ekraani lukustuse menüü on peidetud</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Ekraani lukustuse menüü on nähtav</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Peida Kuula YouTube Musicuga</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Kuula YouTube Musicuga menüü on peidetud</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Kuula YouTube Musicuga menüü on nähtav</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Peida Helitraek</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Helitraekide menüü on peidetud</string>
|
||||
@@ -1639,10 +1641,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -181,9 +181,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -307,7 +306,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Jos Doodle näkyy tällä hetkellä alueellasi ja tämä piilotusasetus on käyt
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Piilota \"Miten sisältö on luotu\"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Miten sisältö on luotu -osio piilotetaan</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Miten sisältö on luotu -osio näytetään</string>
|
||||
<string name="revanced_hide_hype_points_title">Piilota Hype-pisteet</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Hype-pisteet piilotetaan</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Hype-pisteet näytetään</string>
|
||||
<string name="revanced_hide_podcast_section_title">Piilota \"Tutustu podcastiin\"</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Tutustu podcastiin -osio piilotetaan</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Tutustu podcastiin -osio näytetään</string>
|
||||
@@ -771,15 +774,14 @@ Jos tämän asetuksen muuttaminen ei tule voimaan, kokeile vaihtaa Incognito-til
|
||||
<string name="revanced_hide_player_flyout_speed_title">Piilota Toistonopeus</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Toistonopeusvalikko piilotetaan</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Toistonopeusvalikko näytetään</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Piilota Lisätietoja</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Lisätietoja-valinta piilotetaan</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Lisätietoja-valinta näytetään </string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Piilota Näytön lukitus</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Näytön lukitus -valinta piilotetaan</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Näytön lukitus -valinta näytetään</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Piilota Kuuntele YouTube Musicilla</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Kuuntele YouTube Musicilla -valikko on piilotettu</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Kuuntele YouTube Musicilla -valikko on näkyvissä</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Piilota Ääniraita</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Ääniraitavalikko piilotetaan</string>
|
||||
@@ -1158,13 +1160,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_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_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_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_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_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_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>
|
||||
@@ -1182,7 +1184,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_middle">Ohita esikatselu</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_unsubmitted">Ohita osio</string>
|
||||
<string name="revanced_sb_skipped_sponsor">Sponsori ohitettiin</string>
|
||||
@@ -1193,11 +1195,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_end">Tauko 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_middle">Esikatselu 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_unsubmitted">Lähettämätön osio ohitettiin</string>
|
||||
<string name="revanced_sb_skipped_multiple_segments">Useita osioita ohitettiin</string>
|
||||
@@ -1254,7 +1256,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_stats_title">Tilastot</string>
|
||||
<!-- 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_sb_disabled">SponsorBlock ei ole käytössä</string>
|
||||
<string name="revanced_sb_stats_username">Käyttäjänimesi: <b>%s</b></string>
|
||||
@@ -1265,11 +1267,11 @@ Oletko valmis lähettämään?"</string>
|
||||
<string name="revanced_sb_stats_submissions">Olet luonut <b>%s</b> osiota</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">Olet pelastanut ihmisiä <b>%s</b> segmentiltä</string>
|
||||
<string name="revanced_sb_stats_saved">Olet pelastanut ihmisiä <b>%s</b> 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">Se on <b>%s</b> heidän elämistään.<br>Napauta tästä nähdäksesi tulostaulun</string>
|
||||
<string name="revanced_sb_stats_self_saved">Olet ohittanut <b>%s</b> osiota</string>
|
||||
<string name="revanced_sb_stats_self_saved_sum">Tuo on <b>%s</b></string>
|
||||
<string name="revanced_sb_stats_self_saved_sum">Se on <b>%s</b></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_minute_format">%1$s minuuttia %2$s sekuntia</string>
|
||||
@@ -1639,10 +1641,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -328,6 +328,9 @@ Kung ang isang Doodle ay kasalukuyang ipinapakita sa iyong rehiyon at ang settin
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Itago ang \'Paano ginawa ang content na ito\'</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">Nakatago ang seksyon ng Paano ginawa ang content na ito</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">Ipinapakita ang seksyon ng Paano ginawa ang content na ito</string>
|
||||
<string name="revanced_hide_hype_points_title">Itago ang mga Puntos ng Hype</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Nakatago ang mga Puntos ng Hype</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Ipinapakita ang mga Puntos ng Hype</string>
|
||||
<string name="revanced_hide_podcast_section_title">Itago ang \'I-explore ang podcast\'</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Nakatago ang seksyon ng I-explore ang podcast</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Ipinapakita ang seksyon ng I-explore ang podcast</string>
|
||||
@@ -769,15 +772,14 @@ Tandaan: Ang pagpapagana nito ay nagtatago rin ng mga ad ng video"</string>
|
||||
<string name="revanced_hide_player_flyout_speed_title">Itago ang bilis ng pag-playback</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Nakatago ang menu ng bilis ng pag-playback</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Ang menu ng bilis ng pag-playback ay ipinapakita</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Itago ang Higit pang impormasyon</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Nakatago ang menu ng higit pang impormasyon</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Ang menu ng higit pang impormasyon ay ipinapakita</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Itago ang Lock screen</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Nakatago ang menu ng lock screen</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Ipinapakita ang menu ng lock screen</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Itago ang Makinig gamit ang YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Nakatago ang menu ng Makinig gamit ang YouTube Music</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Ipinapakita ang menu ng Makinig gamit ang YouTube Music</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Itago ang Audio track</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Nakatago ang menu ng audio track</string>
|
||||
@@ -1637,10 +1639,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -26,12 +26,12 @@ Second \"item\" text"</string>
|
||||
<!-- 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_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 -->
|
||||
<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 -->
|
||||
<string name="revanced_custom_branding_icon_entry_5">Personnalisé</string>
|
||||
<string name="revanced_custom_branding_icon_entry_5">Personnalisée</string>
|
||||
</patch>
|
||||
<patch id="misc.checks.checkEnvironmentPatch">
|
||||
<string name="revanced_check_environment_failed_title">Les vérifications ont échoué</string>
|
||||
@@ -328,6 +328,9 @@ Si un Doodle est actuellement affiché dans votre région et que cette option de
|
||||
<string name="revanced_hide_how_this_was_made_section_title">Masquer \"Comment ce contenu a été créé\"</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_on">La section \"Comment ce contenu a été créé\" est masquée</string>
|
||||
<string name="revanced_hide_how_this_was_made_section_summary_off">La section \"Comment ce contenu a été créé\" est affichée</string>
|
||||
<string name="revanced_hide_hype_points_title">Masquer les points Boost</string>
|
||||
<string name="revanced_hide_hype_points_summary_on">Les points Boost sont masqués</string>
|
||||
<string name="revanced_hide_hype_points_summary_off">Les points Boost sont affichés</string>
|
||||
<string name="revanced_hide_podcast_section_title">Masquer \"Découvrir le podcast\"</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">La section \"Découvrir le podcast\" est masquée</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">La section \"Découvrir le podcast\" est affichée</string>
|
||||
@@ -771,15 +774,14 @@ Si la modification de ce paramètre ne prend pas effet, essayez de passer en mod
|
||||
<string name="revanced_hide_player_flyout_speed_title">Masquer \"Vitesse de lecture\"</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Le menu Vitesse de lecture est masqué</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Le menu Vitesse de lecture est affiché</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">Masquer \"Plus d\'infos\"</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">Le menu Plus d\'infos est masqué</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">Le menu Plus d\'infos est affiché</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">Masquer \"Verrouiller l\'écran\"</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Le menu Verrouiller l\'écran est masqué</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Le menu Verrouiller l\'écran est affiché</string>
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_title">Masquer \"Écouter avec YouTube Music\"</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_on">Le menu Écouter avec YouTube Music est masqué</string>
|
||||
<string name="revanced_hide_player_flyout_listen_with_youtube_music_summary_off">Le menu Écouter avec YouTube Music est affiché</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Masquer \"Piste audio\"</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Le menu Piste audio est masqué</string>
|
||||
@@ -1363,7 +1365,7 @@ Limitation : Il se peut que le bouton Retour dans la barre d'outils ne fonction
|
||||
</patch>
|
||||
<patch id="layout.miniplayer.miniplayerPatch">
|
||||
<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_entry_0">Désactivé</string>
|
||||
<string name="revanced_miniplayer_type_entry_1">Par défaut</string>
|
||||
@@ -1623,11 +1625,11 @@ Limitations :
|
||||
<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
|
||||
|
||||
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_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_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>
|
||||
@@ -1640,10 +1642,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_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_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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -134,9 +134,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -257,7 +256,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -136,9 +136,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -259,7 +258,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.
|
||||
@@ -135,9 +135,8 @@ Second \"item\" text"</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Listen with YouTube Music' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
@@ -258,7 +257,6 @@ Second \"item\" text"</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
|
||||
<!-- "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>
|
||||
</app>
|
||||
<app id="music">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user