Compare commits

...

56 Commits

Author SHA1 Message Date
semantic-release-bot
04057c6e56 chore: Release v5.40.0-dev.2 [skip ci]
# [5.40.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.40.0-dev.1...v5.40.0-dev.2) (2025-09-18)

### Features

* **Instagram:** Add `Limit feed to followed profiles` patch ([#5908](https://github.com/ReVanced/revanced-patches/issues/5908)) ([8ba9a19](8ba9a19ade))
2025-09-18 06:16:27 +00:00
brosssh
8ba9a19ade feat(Instagram): Add Limit feed to followed profiles patch (#5908) 2025-09-18 10:13:46 +04:00
LisoUseInAIKyrios
6862200a28 chore: Fix api dump 2025-09-17 23:42:11 +04:00
semantic-release-bot
dfff3d7c0a chore: Release v5.40.0-dev.1 [skip ci]
# [5.40.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.39.1-dev.1...v5.40.0-dev.1) (2025-09-17)

### Features

* **Viber - Hide ads:** Support latest app target ([#5863](https://github.com/ReVanced/revanced-patches/issues/5863)) ([e6cce85](e6cce85541))
2025-09-17 17:54:19 +00:00
Samo Hribar
e6cce85541 feat(Viber - Hide ads): Support latest app target (#5863) 2025-09-17 21:51:33 +04:00
github-actions[bot]
8502eb8eac chore: Sync translations (#5918) 2025-09-17 21:51:15 +04:00
semantic-release-bot
0652c56d0d chore: Release v5.39.1-dev.1 [skip ci]
## [5.39.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.39.0...v5.39.1-dev.1) (2025-09-17)

### Bug Fixes

* **YouTube - Force original audio:** Show UI setting summary if spoofing to Android Studio ([b7026b7](b7026b7086))
2025-09-17 16:18:22 +00:00
LisoUseInAIKyrios
b7026b7086 fix(YouTube - Force original audio): Show UI setting summary if spoofing to Android Studio 2025-09-17 20:13:44 +04:00
semantic-release-bot
fa4f422a15 chore: Release v5.39.0 [skip ci]
# [5.39.0](https://github.com/ReVanced/revanced-patches/compare/v5.38.0...v5.39.0) (2025-09-17)

### Bug Fixes

* **YouTube - Spoof video streams:** Do not use Android Creator for livestreams ([cbe576b](cbe576bc38))
* **YouTube - Spoof video streams:** Show Android Studio in spoof stream menu ([c9f741e](c9f741e616))
* **YouTube Music - Spoof video streams:** Remove iPadOS client ([7eeffd3](7eeffd3392))

### Features

* **YouTube - Hide video action buttons:** Add "Hide Shop button" setting ([a84db7b](a84db7be7f))
2025-09-17 09:15:36 +00:00
LisoUseInAIKyrios
38e0cbd724 chore: Merge branch dev to main (#5907) 2025-09-17 13:12:21 +04:00
semantic-release-bot
0bdebd927d chore: Release v5.39.0-dev.2 [skip ci]
# [5.39.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.39.0-dev.1...v5.39.0-dev.2) (2025-09-17)

### Bug Fixes

* **YouTube - Spoof video streams:** Show Android Studio in spoof stream menu ([c9f741e](c9f741e616))
2025-09-17 09:01:12 +00:00
github-actions[bot]
3eac25cf7f chore: Sync translations (#5914) 2025-09-17 12:56:47 +04:00
LisoUseInAIKyrios
c9f741e616 fix(YouTube - Spoof video streams): Show Android Studio in spoof stream menu 2025-09-17 12:54:52 +04:00
semantic-release-bot
cba44ccfc8 chore: Release v5.39.0-dev.1 [skip ci]
# [5.39.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.38.1-dev.2...v5.39.0-dev.1) (2025-09-17)

### Features

* **YouTube - Hide video action buttons:** Add "Hide Shop button" setting ([a84db7b](a84db7be7f))
2025-09-17 07:19:06 +00:00
LisoUseInAIKyrios
a84db7be7f feat(YouTube - Hide video action buttons): Add "Hide Shop button" setting 2025-09-17 11:14:24 +04:00
semantic-release-bot
2520129ace chore: Release v5.38.1-dev.2 [skip ci]
## [5.38.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.38.1-dev.1...v5.38.1-dev.2) (2025-09-16)

### Bug Fixes

* **YouTube Music - Spoof video streams:** Remove iPadOS client ([7eeffd3](7eeffd3392))
2025-09-16 21:49:36 +00:00
LisoUseInAIKyrios
7eeffd3392 fix(YouTube Music - Spoof video streams): Remove iPadOS client 2025-09-17 01:44:48 +04:00
LisoUseInAIKyrios
6c3391164e chore: Remove spoof stream data migration since iPadOS can cause 1 minute playback failure for users in some regions 2025-09-16 23:44:01 +04:00
semantic-release-bot
0b8b46c73e chore: Release v5.38.1-dev.1 [skip ci]
## [5.38.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.38.0...v5.38.1-dev.1) (2025-09-16)

### Bug Fixes

* **YouTube - Spoof video streams:** Do not use Android Creator for livestreams ([cbe576b](cbe576bc38))
2025-09-16 19:27:03 +00:00
LisoUseInAIKyrios
cbe576bc38 fix(YouTube - Spoof video streams): Do not use Android Creator for livestreams 2025-09-16 23:24:07 +04:00
github-actions[bot]
3a29f2a805 chore: Sync translations (#5909) 2025-09-16 23:21:01 +04:00
LisoUseInAIKyrios
50069c7e05 chore: Fix merge typo 2025-09-16 17:26:48 +04:00
semantic-release-bot
2e9c9dc244 chore: Release v5.38.0 [skip ci]
# [5.38.0](https://github.com/ReVanced/revanced-patches/compare/v5.37.0...v5.38.0) (2025-09-16)

### Bug Fixes

* **Instagram - Hide navigation buttons:** Support v397.1.0.52.81 ([#5855](https://github.com/ReVanced/revanced-patches/issues/5855)) ([f11d1ef](f11d1ef990))
* **Spoof video streams:** Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for `Force original audio` to work with any spoof client ([#5861](https://github.com/ReVanced/revanced-patches/issues/5861)) ([abe3943](abe3943f98))
* **YouTube - Spoof video streams:** Show settings summary if `Force original audio` is enabled ([3776dda](3776dda710))
* **YouTube Music - Spoof video streams:** Fix playback issues when using a cellular network ([fa04c8e](fa04c8eecf))
* **YouTube Music:** Use correct light/dark mode settings UI ([1475643](1475643f84))

### Features

* **Instagram:** Add `Hide explore feed` patch ([#5856](https://github.com/ReVanced/revanced-patches/issues/5856)) ([1d65887](1d65887e01))
* **YouTube - Spoof video streams:** Add iPadOS client ([2726231](2726231404))
* **YouTube Music:** Add `Settings` patch ([#5838](https://github.com/ReVanced/revanced-patches/issues/5838)) ([5e20bd8](5e20bd80f1))
2025-09-16 13:01:23 +00:00
LisoUseInAIKyrios
56166896d9 chore: Merge branch dev to main (#5857) 2025-09-16 16:57:55 +04:00
semantic-release-bot
b4c695b1d5 chore: Release v5.38.0-dev.5 [skip ci]
# [5.38.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.4...v5.38.0-dev.5) (2025-09-16)

### Bug Fixes

* **YouTube Music:** Use correct light/dark mode settings UI ([1475643](1475643f84))
2025-09-16 12:34:52 +00:00
LisoUseInAIKyrios
1475643f84 fix(YouTube Music): Use correct light/dark mode settings UI 2025-09-16 16:31:04 +04:00
github-actions[bot]
9a7179f9cf chore: Sync translations (#5906) 2025-09-16 16:29:53 +04:00
semantic-release-bot
6fb94a7a41 chore: Release v5.38.0-dev.4 [skip ci]
# [5.38.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.3...v5.38.0-dev.4) (2025-09-16)

### Bug Fixes

* **YouTube - Spoof video streams:** Show settings summary if `Force original audio` is enabled ([3776dda](3776dda710))
2025-09-16 12:05:23 +00:00
LisoUseInAIKyrios
3776dda710 fix(YouTube - Spoof video streams): Show settings summary if Force original audio is enabled 2025-09-16 15:59:32 +04:00
LisoUseInAIKyrios
f88b3a5162 refactor(YouTube - Spoof video streams): Adjust preferred client order 2025-09-16 15:40:55 +04:00
semantic-release-bot
0eeaf7ad67 chore: Release v5.38.0-dev.3 [skip ci]
# [5.38.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.2...v5.38.0-dev.3) (2025-09-16)

### Features

* **YouTube - Spoof video streams:** Add iPadOS client ([2726231](2726231404))
2025-09-16 11:36:54 +00:00
LisoUseInAIKyrios
2726231404 feat(YouTube - Spoof video streams): Add iPadOS client 2025-09-16 15:33:55 +04:00
github-actions[bot]
9f0558e494 chore: Sync translations (#5905) 2025-09-16 15:11:04 +04:00
semantic-release-bot
01f7bc9f8d chore: Release v5.38.0-dev.2 [skip ci]
# [5.38.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.1...v5.38.0-dev.2) (2025-09-16)

### Features

* **YouTube Music:** Add `Settings` patch ([#5838](https://github.com/ReVanced/revanced-patches/issues/5838)) ([5e20bd8](5e20bd80f1))
2025-09-16 06:57:43 +00:00
MarcaD
5e20bd80f1 feat(YouTube Music): Add Settings patch (#5838)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-09-16 10:53:49 +04:00
semantic-release-bot
f304c178e2 chore: Release v5.38.0-dev.1 [skip ci]
# [5.38.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.3...v5.38.0-dev.1) (2025-09-15)

### Features

* **Instagram:** Add `Hide explore feed` patch ([#5856](https://github.com/ReVanced/revanced-patches/issues/5856)) ([1d65887](1d65887e01))
2025-09-15 19:30:52 +00:00
brosssh
1d65887e01 feat(Instagram): Add Hide explore feed patch (#5856) 2025-09-15 23:28:01 +04:00
github-actions[bot]
6b6eea8414 chore: Sync translations (#5864) 2025-09-15 23:26:07 +04:00
semantic-release-bot
1db131e90e chore: Release v5.37.1-dev.3 [skip ci]
## [5.37.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.2...v5.37.1-dev.3) (2025-09-15)

### Bug Fixes

* **Spoof video streams:** Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for `Force original audio` to work with any spoof client ([#5861](https://github.com/ReVanced/revanced-patches/issues/5861)) ([abe3943](abe3943f98))
2025-09-15 17:02:01 +00:00
LisoUseInAIKyrios
abe3943f98 fix(Spoof video streams): Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for Force original audio to work with any spoof client (#5861) 2025-09-15 20:58:56 +04:00
semantic-release-bot
cb6d802de3 chore: Release v5.37.1-dev.2 [skip ci]
## [5.37.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.1...v5.37.1-dev.2) (2025-09-15)

### Bug Fixes

* **Instagram - Hide navigation buttons:** Support v397.1.0.52.81 ([#5855](https://github.com/ReVanced/revanced-patches/issues/5855)) ([f11d1ef](f11d1ef990))
2025-09-15 12:52:54 +00:00
brosssh
f11d1ef990 fix(Instagram - Hide navigation buttons): Support v397.1.0.52.81 (#5855) 2025-09-15 16:48:55 +04:00
semantic-release-bot
3d25da18bc chore: Release v5.37.1-dev.1 [skip ci]
## [5.37.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.37.0...v5.37.1-dev.1) (2025-09-15)

### Bug Fixes

* **YouTube Music - Spoof video streams:** Fix playback issues when using a cellular network ([fa04c8e](fa04c8eecf))
2025-09-15 12:47:02 +00:00
LisoUseInAIKyrios
fa04c8eecf fix(YouTube Music - Spoof video streams): Fix playback issues when using a cellular network
Code adapted from 5f35e51a27
2025-09-15 16:43:04 +04:00
semantic-release-bot
105f6e0e97 chore: Release v5.37.0 [skip ci]
# [5.37.0](https://github.com/ReVanced/revanced-patches/compare/v5.36.0...v5.37.0) (2025-09-15)

### Bug Fixes

* **Instagram - Hide navigation buttons:** Add constrain to known working version ([e6c79f1](e6c79f1383))
* Resolve patching with dev branch ([09b941a](09b941abf0))
* **Spotify:** Remove broken `Spoof client` patch ([#5833](https://github.com/ReVanced/revanced-patches/issues/5833)) ([dcd4245](dcd42454bd))
* **Viber - Hide ads:** Add constrain to known working version ([2db0948](2db0948bea))
* **YouTube Music - Spoof streaming data:** Fix audio playback stuttering ([#5839](https://github.com/ReVanced/revanced-patches/issues/5839)) ([2a85a3b](2a85a3b290))

### Features

* **Viber:** Add `Hide ads` patch ([#5826](https://github.com/ReVanced/revanced-patches/issues/5826)) ([0abfab7](0abfab79d7))
2025-09-15 06:45:56 +00:00
LisoUseInAIKyrios
7d59efe05d chore: Merge branch dev to main (#5830) 2025-09-15 10:43:05 +04:00
github-actions[bot]
81ff5576b0 chore: Sync translations (#5854) 2025-09-15 10:41:42 +04:00
semantic-release-bot
9a5c102c0d chore: Release v5.37.0-dev.6 [skip ci]
# [5.37.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.5...v5.37.0-dev.6) (2025-09-15)

### Bug Fixes

* **Instagram - Hide navigation buttons:** Add constrain to known working version ([e6c79f1](e6c79f1383))
2025-09-15 06:40:30 +00:00
LisoUseInAIKyrios
e6c79f1383 fix(Instagram - Hide navigation buttons): Add constrain to known working version 2025-09-15 10:36:57 +04:00
semantic-release-bot
2a582eced8 chore: Release v5.37.0-dev.5 [skip ci]
# [5.37.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.4...v5.37.0-dev.5) (2025-09-15)

### Bug Fixes

* **Viber - Hide ads:** Add constrain to known working version ([2db0948](2db0948bea))
2025-09-15 06:29:31 +00:00
LisoUseInAIKyrios
2db0948bea fix(Viber - Hide ads): Add constrain to known working version 2025-09-15 10:26:30 +04:00
semantic-release-bot
a3ba92e742 chore: Release v5.37.0-dev.4 [skip ci]
# [5.37.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.3...v5.37.0-dev.4) (2025-09-14)

### Bug Fixes

* **YouTube Music - Spoof streaming data:** Fix audio playback stuttering ([#5839](https://github.com/ReVanced/revanced-patches/issues/5839)) ([2a85a3b](2a85a3b290))
2025-09-14 18:22:57 +00:00
LisoUseInAIKyrios
2a85a3b290 fix(YouTube Music - Spoof streaming data): Fix audio playback stuttering (#5839) 2025-09-14 22:19:13 +04:00
semantic-release-bot
eee72208dd chore: Release v5.37.0-dev.3 [skip ci]
# [5.37.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.2...v5.37.0-dev.3) (2025-09-14)

### Bug Fixes

* **Spotify:** Remove broken `Spoof client` patch ([#5833](https://github.com/ReVanced/revanced-patches/issues/5833)) ([dcd4245](dcd42454bd))
2025-09-14 17:15:28 +00:00
LisoUseInAIKyrios
dcd42454bd fix(Spotify): Remove broken Spoof client patch (#5833) 2025-09-14 21:11:15 +04:00
LisoUseInAIKyrios
782353c18a refactor(Spoof video streams): Handle migration of default spoof client for users upgrading from very old patches 2025-09-14 18:06:40 +04:00
173 changed files with 6461 additions and 2638 deletions

View File

@@ -1,3 +1,184 @@
# [5.40.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.40.0-dev.1...v5.40.0-dev.2) (2025-09-18)
### Features
* **Instagram:** Add `Limit feed to followed profiles` patch ([#5908](https://github.com/ReVanced/revanced-patches/issues/5908)) ([8ba9a19](https://github.com/ReVanced/revanced-patches/commit/8ba9a19ade24c5fe9bd6d4e49772b7663522780e))
# [5.40.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.39.1-dev.1...v5.40.0-dev.1) (2025-09-17)
### Features
* **Viber - Hide ads:** Support latest app target ([#5863](https://github.com/ReVanced/revanced-patches/issues/5863)) ([e6cce85](https://github.com/ReVanced/revanced-patches/commit/e6cce8554116df3c0ea6dbb7440c59c9e73d8334))
## [5.39.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.39.0...v5.39.1-dev.1) (2025-09-17)
### Bug Fixes
* **YouTube - Force original audio:** Show UI setting summary if spoofing to Android Studio ([b7026b7](https://github.com/ReVanced/revanced-patches/commit/b7026b70865bc44de07b30f84ba8b8b608930d5b))
# [5.39.0](https://github.com/ReVanced/revanced-patches/compare/v5.38.0...v5.39.0) (2025-09-17)
### Bug Fixes
* **YouTube - Spoof video streams:** Do not use Android Creator for livestreams ([cbe576b](https://github.com/ReVanced/revanced-patches/commit/cbe576bc384ef5f5ee2fa341147925ed0dff568b))
* **YouTube - Spoof video streams:** Show Android Studio in spoof stream menu ([c9f741e](https://github.com/ReVanced/revanced-patches/commit/c9f741e616c7acab0cd4558e02b0c4ec18392c10))
* **YouTube Music - Spoof video streams:** Remove iPadOS client ([7eeffd3](https://github.com/ReVanced/revanced-patches/commit/7eeffd3392c57555342173103d3a417c038d0970))
### Features
* **YouTube - Hide video action buttons:** Add "Hide Shop button" setting ([a84db7b](https://github.com/ReVanced/revanced-patches/commit/a84db7be7fde2e9bb3ac41aec709a1681e845fe1))
# [5.39.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.39.0-dev.1...v5.39.0-dev.2) (2025-09-17)
### Bug Fixes
* **YouTube - Spoof video streams:** Show Android Studio in spoof stream menu ([c9f741e](https://github.com/ReVanced/revanced-patches/commit/c9f741e616c7acab0cd4558e02b0c4ec18392c10))
# [5.39.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.38.1-dev.2...v5.39.0-dev.1) (2025-09-17)
### Features
* **YouTube - Hide video action buttons:** Add "Hide Shop button" setting ([a84db7b](https://github.com/ReVanced/revanced-patches/commit/a84db7be7fde2e9bb3ac41aec709a1681e845fe1))
## [5.38.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.38.1-dev.1...v5.38.1-dev.2) (2025-09-16)
### Bug Fixes
* **YouTube Music - Spoof video streams:** Remove iPadOS client ([7eeffd3](https://github.com/ReVanced/revanced-patches/commit/7eeffd3392c57555342173103d3a417c038d0970))
## [5.38.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.38.0...v5.38.1-dev.1) (2025-09-16)
### Bug Fixes
* **YouTube - Spoof video streams:** Do not use Android Creator for livestreams ([cbe576b](https://github.com/ReVanced/revanced-patches/commit/cbe576bc384ef5f5ee2fa341147925ed0dff568b))
# [5.38.0](https://github.com/ReVanced/revanced-patches/compare/v5.37.0...v5.38.0) (2025-09-16)
### Bug Fixes
* **Instagram - Hide navigation buttons:** Support v397.1.0.52.81 ([#5855](https://github.com/ReVanced/revanced-patches/issues/5855)) ([f11d1ef](https://github.com/ReVanced/revanced-patches/commit/f11d1ef9907082512f139d4ab0e2e9f707de7e48))
* **Spoof video streams:** Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for `Force original audio` to work with any spoof client ([#5861](https://github.com/ReVanced/revanced-patches/issues/5861)) ([abe3943](https://github.com/ReVanced/revanced-patches/commit/abe3943f98fd86dcd74c7e07cf65d3c7fc24fef9))
* **YouTube - Spoof video streams:** Show settings summary if `Force original audio` is enabled ([3776dda](https://github.com/ReVanced/revanced-patches/commit/3776dda710a7780717b7e6f2cdc1333ab67b92fc))
* **YouTube Music - Spoof video streams:** Fix playback issues when using a cellular network ([fa04c8e](https://github.com/ReVanced/revanced-patches/commit/fa04c8eecfbdd0b6ed082b464ca9032536d71762))
* **YouTube Music:** Use correct light/dark mode settings UI ([1475643](https://github.com/ReVanced/revanced-patches/commit/1475643f84e9ee4af2ba360a2274001ff1570dad))
### Features
* **Instagram:** Add `Hide explore feed` patch ([#5856](https://github.com/ReVanced/revanced-patches/issues/5856)) ([1d65887](https://github.com/ReVanced/revanced-patches/commit/1d65887e015a067196f5a84db486fff355c96596))
* **YouTube - Spoof video streams:** Add iPadOS client ([2726231](https://github.com/ReVanced/revanced-patches/commit/2726231404384d87f101d825e10a17c944e8f1bd))
* **YouTube Music:** Add `Settings` patch ([#5838](https://github.com/ReVanced/revanced-patches/issues/5838)) ([5e20bd8](https://github.com/ReVanced/revanced-patches/commit/5e20bd80f138d7ca94f18857194c46e489c435dc))
# [5.38.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.4...v5.38.0-dev.5) (2025-09-16)
### Bug Fixes
* **YouTube Music:** Use correct light/dark mode settings UI ([1475643](https://github.com/ReVanced/revanced-patches/commit/1475643f84e9ee4af2ba360a2274001ff1570dad))
# [5.38.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.3...v5.38.0-dev.4) (2025-09-16)
### Bug Fixes
* **YouTube - Spoof video streams:** Show settings summary if `Force original audio` is enabled ([3776dda](https://github.com/ReVanced/revanced-patches/commit/3776dda710a7780717b7e6f2cdc1333ab67b92fc))
# [5.38.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.2...v5.38.0-dev.3) (2025-09-16)
### Features
* **YouTube - Spoof video streams:** Add iPadOS client ([2726231](https://github.com/ReVanced/revanced-patches/commit/2726231404384d87f101d825e10a17c944e8f1bd))
# [5.38.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.38.0-dev.1...v5.38.0-dev.2) (2025-09-16)
### Features
* **YouTube Music:** Add `Settings` patch ([#5838](https://github.com/ReVanced/revanced-patches/issues/5838)) ([5e20bd8](https://github.com/ReVanced/revanced-patches/commit/5e20bd80f138d7ca94f18857194c46e489c435dc))
# [5.38.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.3...v5.38.0-dev.1) (2025-09-15)
### Features
* **Instagram:** Add `Hide explore feed` patch ([#5856](https://github.com/ReVanced/revanced-patches/issues/5856)) ([1d65887](https://github.com/ReVanced/revanced-patches/commit/1d65887e015a067196f5a84db486fff355c96596))
## [5.37.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.2...v5.37.1-dev.3) (2025-09-15)
### Bug Fixes
* **Spoof video streams:** Remove Android TV and iOS TV clients, add experimental VisionOS, add temporary fix for `Force original audio` to work with any spoof client ([#5861](https://github.com/ReVanced/revanced-patches/issues/5861)) ([abe3943](https://github.com/ReVanced/revanced-patches/commit/abe3943f98fd86dcd74c7e07cf65d3c7fc24fef9))
## [5.37.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.37.1-dev.1...v5.37.1-dev.2) (2025-09-15)
### Bug Fixes
* **Instagram - Hide navigation buttons:** Support v397.1.0.52.81 ([#5855](https://github.com/ReVanced/revanced-patches/issues/5855)) ([f11d1ef](https://github.com/ReVanced/revanced-patches/commit/f11d1ef9907082512f139d4ab0e2e9f707de7e48))
## [5.37.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.37.0...v5.37.1-dev.1) (2025-09-15)
### Bug Fixes
* **YouTube Music - Spoof video streams:** Fix playback issues when using a cellular network ([fa04c8e](https://github.com/ReVanced/revanced-patches/commit/fa04c8eecfbdd0b6ed082b464ca9032536d71762))
# [5.37.0](https://github.com/ReVanced/revanced-patches/compare/v5.36.0...v5.37.0) (2025-09-15)
### Bug Fixes
* **Instagram - Hide navigation buttons:** Add constrain to known working version ([e6c79f1](https://github.com/ReVanced/revanced-patches/commit/e6c79f13834c83fef04e4dee5e628cb0b9a27765))
* Resolve patching with dev branch ([09b941a](https://github.com/ReVanced/revanced-patches/commit/09b941abf0e8029999565082b02a88b5de507ec4))
* **Spotify:** Remove broken `Spoof client` patch ([#5833](https://github.com/ReVanced/revanced-patches/issues/5833)) ([dcd4245](https://github.com/ReVanced/revanced-patches/commit/dcd42454bd5f87dddd720534f6120c4ef90063a3))
* **Viber - Hide ads:** Add constrain to known working version ([2db0948](https://github.com/ReVanced/revanced-patches/commit/2db0948beaf2b68391a1fe7f21e92d31c7df61e7))
* **YouTube Music - Spoof streaming data:** Fix audio playback stuttering ([#5839](https://github.com/ReVanced/revanced-patches/issues/5839)) ([2a85a3b](https://github.com/ReVanced/revanced-patches/commit/2a85a3b29092729ae16d1fd93803634ce5f08e95))
### Features
* **Viber:** Add `Hide ads` patch ([#5826](https://github.com/ReVanced/revanced-patches/issues/5826)) ([0abfab7](https://github.com/ReVanced/revanced-patches/commit/0abfab79d7cda15bf17c53679fbfffb021662649))
# [5.37.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.5...v5.37.0-dev.6) (2025-09-15)
### Bug Fixes
* **Instagram - Hide navigation buttons:** Add constrain to known working version ([e6c79f1](https://github.com/ReVanced/revanced-patches/commit/e6c79f13834c83fef04e4dee5e628cb0b9a27765))
# [5.37.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.4...v5.37.0-dev.5) (2025-09-15)
### Bug Fixes
* **Viber - Hide ads:** Add constrain to known working version ([2db0948](https://github.com/ReVanced/revanced-patches/commit/2db0948beaf2b68391a1fe7f21e92d31c7df61e7))
# [5.37.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.3...v5.37.0-dev.4) (2025-09-14)
### Bug Fixes
* **YouTube Music - Spoof streaming data:** Fix audio playback stuttering ([#5839](https://github.com/ReVanced/revanced-patches/issues/5839)) ([2a85a3b](https://github.com/ReVanced/revanced-patches/commit/2a85a3b29092729ae16d1fd93803634ce5f08e95))
# [5.37.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.2...v5.37.0-dev.3) (2025-09-14)
### Bug Fixes
* **Spotify:** Remove broken `Spoof client` patch ([#5833](https://github.com/ReVanced/revanced-patches/issues/5833)) ([dcd4245](https://github.com/ReVanced/revanced-patches/commit/dcd42454bd5f87dddd720534f6120c4ef90063a3))
# [5.37.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.1...v5.37.0-dev.2) (2025-09-14) # [5.37.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.37.0-dev.1...v5.37.0-dev.2) (2025-09-14)

View File

@@ -0,0 +1,3 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
}

View File

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

View File

@@ -0,0 +1,18 @@
package app.revanced.extension.instagram.feed;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("unused")
public class LimitFeedToFollowedProfiles {
/**
* Injection point.
*/
public static Map<String, String> setFollowingHeader(Map<String, String> requestHeaderMap) {
// Create new map as original is unmodifiable.
Map<String, String> patchedRequestHeaderMap = new HashMap<>(requestHeaderMap);
patchedRequestHeaderMap.put("pagination_source", "following");
return patchedRequestHeaderMap;
}
}

View File

@@ -1,3 +1,9 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
compileOnly(project(":extensions:youtube:stub"))
compileOnly(libs.annotation)
}
android { android {
defaultConfig { defaultConfig {
minSdk = 26 minSdk = 26

View File

@@ -0,0 +1,14 @@
package app.revanced.extension.music.patches;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class HideCategoryBarPatch {
/**
* Injection point
*/
public static boolean hideCategoryBar() {
return Settings.HIDE_CATEGORY_BAR.get();
}
}

View File

@@ -0,0 +1,14 @@
package app.revanced.extension.music.patches;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class HideGetPremiumPatch {
/**
* Injection point
*/
public static boolean hideGetPremiumLabel() {
return Settings.HIDE_GET_PREMIUM_LABEL.get();
}
}

View File

@@ -0,0 +1,14 @@
package app.revanced.extension.music.patches;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class HideUpgradeButtonPatch {
/**
* Injection point
*/
public static boolean hideUpgradeButton() {
return Settings.HIDE_UPGRADE_BUTTON.get();
}
}

View File

@@ -0,0 +1,17 @@
package app.revanced.extension.music.patches;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class HideVideoAdsPatch {
/**
* Injection point
*/
public static boolean showVideoAds(boolean original) {
if (Settings.HIDE_VIDEO_ADS.get()) {
return false;
}
return original;
}
}

View File

@@ -0,0 +1,14 @@
package app.revanced.extension.music.patches;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class PermanentRepeatPatch {
/**
* Injection point
*/
public static boolean permanentRepeat() {
return Settings.PERMANENT_REPEAT.get();
}
}

View File

@@ -0,0 +1,28 @@
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_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;
import java.util.List;
import app.revanced.extension.shared.spoof.ClientType;
@SuppressWarnings("unused")
public class SpoofVideoStreamsPatch {
/**
* Injection point.
*/
public static void setClientOrderToUse() {
List<ClientType> availableClients = List.of(
ANDROID_VR_1_43_32,
ANDROID_VR_1_61_48,
VISIONOS
);
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
availableClients, SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
}
}

View File

@@ -0,0 +1,87 @@
package app.revanced.extension.music.settings;
import android.app.Activity;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceFragment;
import android.view.View;
import app.revanced.extension.music.settings.preference.ReVancedPreferenceFragment;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseActivityHook;
/**
* Hooks GoogleApiActivity to inject a custom ReVancedPreferenceFragment with a toolbar.
*/
public class GoogleApiActivityHook extends BaseActivityHook {
/**
* Injection point
* <p>
* Creates an instance of GoogleApiActivityHook for use in static initialization.
*/
@SuppressWarnings("unused")
public static GoogleApiActivityHook createInstance() {
// Must touch the Music settings to ensure the class is loaded and
// the values can be found when setting the UI preferences.
// Logging anything under non debug ensures this is set.
Logger.printInfo(() -> "Permanent repeat enabled: " + Settings.PERMANENT_REPEAT.get());
// YT Music always uses dark mode.
Utils.setIsDarkModeEnabled(true);
return new GoogleApiActivityHook();
}
/**
* Sets the fixed theme for the activity.
*/
@Override
protected void customizeActivityTheme(Activity activity) {
// Override the default YouTube Music theme to increase start padding of list items.
// Custom style located in resources/music/values/style.xml
activity.setTheme(Utils.getResourceIdentifier("Theme.ReVanced.YouTubeMusic.Settings", "style"));
}
/**
* Returns the resource ID for the YouTube Music settings layout.
*/
@Override
protected int getContentViewResourceId() {
return Utils.getResourceIdentifier("revanced_music_settings_with_toolbar", "layout");
}
/**
* Returns the fixed background color for the toolbar.
*/
@Override
protected int getToolbarBackgroundColor() {
return Utils.getResourceColor("ytm_color_black");
}
/**
* Returns the navigation icon with a color filter applied.
*/
@Override
protected Drawable getNavigationIcon() {
Drawable navigationIcon = ReVancedPreferenceFragment.getBackButtonDrawable();
navigationIcon.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN);
return navigationIcon;
}
/**
* Returns the click listener that finishes the activity when the navigation icon is clicked.
*/
@Override
protected View.OnClickListener getNavigationClickListener(Activity activity) {
return view -> activity.finish();
}
/**
* Creates a new ReVancedPreferenceFragment for the activity.
*/
@Override
protected PreferenceFragment createPreferenceFragment() {
return new ReVancedPreferenceFragment();
}
}

View File

@@ -0,0 +1,29 @@
package app.revanced.extension.music.settings;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.settings.Setting.parent;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.BooleanSetting;
import app.revanced.extension.shared.settings.EnumSetting;
import app.revanced.extension.shared.spoof.ClientType;
public class Settings extends BaseSettings {
// Ads
public static final BooleanSetting HIDE_VIDEO_ADS = new BooleanSetting("revanced_music_hide_video_ads", TRUE, true);
public static final BooleanSetting HIDE_GET_PREMIUM_LABEL = new BooleanSetting("revanced_music_hide_get_premium_label", TRUE, true);
public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true);
// General
public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true);
// Player
public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true);
// Miscellaneous
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
}

View File

@@ -0,0 +1,38 @@
package app.revanced.extension.music.settings.preference;
import android.widget.Toolbar;
import app.revanced.extension.music.settings.GoogleApiActivityHook;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
/**
* Preference fragment for ReVanced settings.
*/
@SuppressWarnings({"deprecation", "NewApi"})
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
/**
* Initializes the preference fragment.
*/
@Override
protected void initialize() {
super.initialize();
try {
Utils.sortPreferenceGroups(getPreferenceScreen());
setPreferenceScreenToolbar(getPreferenceScreen());
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}
}
/**
* Sets toolbar for all nested preference screens.
*/
@Override
protected void customizeToolbar(Toolbar toolbar) {
GoogleApiActivityHook.setToolbarLayoutParams(toolbar);
}
}

View File

@@ -1,6 +1,4 @@
package app.revanced.extension.youtube; package app.revanced.extension.shared;
import androidx.annotation.NonNull;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -39,7 +37,7 @@ public final class ByteTrieSearch extends TrieSearch<byte[]> {
return replacement; return replacement;
} }
public ByteTrieSearch(@NonNull byte[]... patterns) { public ByteTrieSearch(byte[]... patterns) {
super(new ByteTrieNode(), patterns); super(new ByteTrieNode(), patterns);
} }
} }

View File

@@ -1,6 +1,4 @@
package app.revanced.extension.youtube; package app.revanced.extension.shared;
import androidx.annotation.NonNull;
/** /**
* Text pattern searching using a prefix tree (trie). * Text pattern searching using a prefix tree (trie).
@@ -28,7 +26,7 @@ public final class StringTrieSearch extends TrieSearch<String> {
} }
} }
public StringTrieSearch(@NonNull String... patterns) { public StringTrieSearch(String... patterns) {
super(new StringTrieNode(), patterns); super(new StringTrieNode(), patterns);
} }
} }

View File

@@ -1,6 +1,5 @@
package app.revanced.extension.youtube; package app.revanced.extension.shared;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -57,11 +56,13 @@ public abstract class TrieSearch<T> {
if (searchTextLength - searchTextIndex < patternLength - patternStartIndex) { if (searchTextLength - searchTextIndex < patternLength - patternStartIndex) {
return false; // Remaining search text is shorter than the remaining leaf pattern and they cannot match. return false; // Remaining search text is shorter than the remaining leaf pattern and they cannot match.
} }
for (int i = searchTextIndex, j = patternStartIndex; j < patternLength; i++, j++) { for (int i = searchTextIndex, j = patternStartIndex; j < patternLength; i++, j++) {
if (enclosingNode.getCharValue(searchText, i) != enclosingNode.getCharValue(pattern, j)) { if (enclosingNode.getCharValue(searchText, i) != enclosingNode.getCharValue(pattern, j)) {
return false; return false;
} }
} }
return callback == null || callback.patternMatched(searchText, return callback == null || callback.patternMatched(searchText,
searchTextIndex - patternStartIndex, patternLength, callbackParameter); searchTextIndex - patternStartIndex, patternLength, callbackParameter);
} }
@@ -136,7 +137,7 @@ public abstract class TrieSearch<T> {
* @param patternLength Length of the pattern. * @param patternLength Length of the pattern.
* @param callback Callback, where a value of NULL indicates to always accept a pattern match. * @param callback Callback, where a value of NULL indicates to always accept a pattern match.
*/ */
private void addPattern(@NonNull T pattern, int patternIndex, int patternLength, private void addPattern(T pattern, int patternIndex, int patternLength,
@Nullable TriePatternMatchedCallback<T> callback) { @Nullable TriePatternMatchedCallback<T> callback) {
if (patternIndex == patternLength) { // Reached the end of the pattern. if (patternIndex == patternLength) { // Reached the end of the pattern.
if (endOfPatternCallback == null) { if (endOfPatternCallback == null) {
@@ -145,6 +146,7 @@ public abstract class TrieSearch<T> {
endOfPatternCallback.add(callback); endOfPatternCallback.add(callback);
return; return;
} }
if (leaf != null) { if (leaf != null) {
// Reached end of the graph and a leaf exist. // Reached end of the graph and a leaf exist.
// Recursively call back into this method and push the existing leaf down 1 level. // Recursively call back into this method and push the existing leaf down 1 level.
@@ -159,6 +161,7 @@ public abstract class TrieSearch<T> {
leaf = new TrieCompressedPath<>(pattern, patternIndex, patternLength, callback); leaf = new TrieCompressedPath<>(pattern, patternIndex, patternLength, callback);
return; return;
} }
final char character = getCharValue(pattern, patternIndex); final char character = getCharValue(pattern, patternIndex);
final int arrayIndex = hashIndexForTableSize(children.length, character); final int arrayIndex = hashIndexForTableSize(children.length, character);
TrieNode<T> child = children[arrayIndex]; TrieNode<T> child = children[arrayIndex];
@@ -183,6 +186,7 @@ public abstract class TrieSearch<T> {
//noinspection unchecked //noinspection unchecked
TrieNode<T>[] replacement = new TrieNode[replacementArraySize]; TrieNode<T>[] replacement = new TrieNode[replacementArraySize];
addNodeToArray(replacement, child); addNodeToArray(replacement, child);
boolean collision = false; boolean collision = false;
for (TrieNode<T> existingChild : children) { for (TrieNode<T> existingChild : children) {
if (existingChild != null) { if (existingChild != null) {
@@ -195,6 +199,7 @@ public abstract class TrieSearch<T> {
if (collision) { if (collision) {
continue; continue;
} }
children = replacement; children = replacement;
return; return;
} }
@@ -234,6 +239,7 @@ public abstract class TrieSearch<T> {
if (leaf != null && leaf.matches(startNode, searchText, searchTextEndIndex, searchTextIndex, callbackParameter)) { if (leaf != null && leaf.matches(startNode, searchText, searchTextEndIndex, searchTextIndex, callbackParameter)) {
return true; // Leaf exists and it matched the search text. return true; // Leaf exists and it matched the search text.
} }
List<TriePatternMatchedCallback<T>> endOfPatternCallback = node.endOfPatternCallback; List<TriePatternMatchedCallback<T>> endOfPatternCallback = node.endOfPatternCallback;
if (endOfPatternCallback != null) { if (endOfPatternCallback != null) {
final int matchStartIndex = searchTextIndex - currentMatchLength; final int matchStartIndex = searchTextIndex - currentMatchLength;
@@ -246,6 +252,7 @@ public abstract class TrieSearch<T> {
} }
} }
} }
TrieNode<T>[] children = node.children; TrieNode<T>[] children = node.children;
if (children == null) { if (children == null) {
return false; // Reached a graph end point and there's no further patterns to search. return false; // Reached a graph end point and there's no further patterns to search.
@@ -278,9 +285,11 @@ public abstract class TrieSearch<T> {
if (leaf != null) { if (leaf != null) {
numberOfPointers += 4; // Number of fields in leaf node. numberOfPointers += 4; // Number of fields in leaf node.
} }
if (endOfPatternCallback != null) { if (endOfPatternCallback != null) {
numberOfPointers += endOfPatternCallback.size(); numberOfPointers += endOfPatternCallback.size();
} }
if (children != null) { if (children != null) {
numberOfPointers += children.length; numberOfPointers += children.length;
for (TrieNode<T> child : children) { for (TrieNode<T> child : children) {
@@ -308,13 +317,13 @@ public abstract class TrieSearch<T> {
private final List<T> patterns = new ArrayList<>(); private final List<T> patterns = new ArrayList<>();
@SafeVarargs @SafeVarargs
TrieSearch(@NonNull TrieNode<T> root, @NonNull T... patterns) { TrieSearch(TrieNode<T> root, T... patterns) {
this.root = Objects.requireNonNull(root); this.root = Objects.requireNonNull(root);
addPatterns(patterns); addPatterns(patterns);
} }
@SafeVarargs @SafeVarargs
public final void addPatterns(@NonNull T... patterns) { public final void addPatterns(T... patterns) {
for (T pattern : patterns) { for (T pattern : patterns) {
addPattern(pattern); addPattern(pattern);
} }
@@ -325,7 +334,7 @@ public abstract class TrieSearch<T> {
* *
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing. * @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
*/ */
public void addPattern(@NonNull T pattern) { public void addPattern(T pattern) {
addPattern(pattern, root.getTextLength(pattern), null); addPattern(pattern, root.getTextLength(pattern), null);
} }
@@ -333,31 +342,31 @@ public abstract class TrieSearch<T> {
* @param pattern Pattern to add. Calling this with a zero length pattern does nothing. * @param pattern Pattern to add. Calling this with a zero length pattern does nothing.
* @param callback Callback to determine if searching should halt when a match is found. * @param callback Callback to determine if searching should halt when a match is found.
*/ */
public void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback<T> callback) { public void addPattern(T pattern, TriePatternMatchedCallback<T> callback) {
addPattern(pattern, root.getTextLength(pattern), Objects.requireNonNull(callback)); addPattern(pattern, root.getTextLength(pattern), Objects.requireNonNull(callback));
} }
void addPattern(@NonNull T pattern, int patternLength, @Nullable TriePatternMatchedCallback<T> callback) { void addPattern(T pattern, int patternLength, @Nullable TriePatternMatchedCallback<T> callback) {
if (patternLength == 0) return; // Nothing to match if (patternLength == 0) return; // Nothing to match
patterns.add(pattern); patterns.add(pattern);
root.addPattern(pattern, 0, patternLength, callback); root.addPattern(pattern, 0, patternLength, callback);
} }
public final boolean matches(@NonNull T textToSearch) { public final boolean matches(T textToSearch) {
return matches(textToSearch, 0); return matches(textToSearch, 0);
} }
public boolean matches(@NonNull T textToSearch, @NonNull Object callbackParameter) { public boolean matches(T textToSearch, Object callbackParameter) {
return matches(textToSearch, 0, root.getTextLength(textToSearch), return matches(textToSearch, 0, root.getTextLength(textToSearch),
Objects.requireNonNull(callbackParameter)); Objects.requireNonNull(callbackParameter));
} }
public boolean matches(@NonNull T textToSearch, int startIndex) { public boolean matches(T textToSearch, int startIndex) {
return matches(textToSearch, startIndex, root.getTextLength(textToSearch)); return matches(textToSearch, startIndex, root.getTextLength(textToSearch));
} }
public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) { public final boolean matches(T textToSearch, int startIndex, int endIndex) {
return matches(textToSearch, startIndex, endIndex, null); return matches(textToSearch, startIndex, endIndex, null);
} }
@@ -370,11 +379,11 @@ public abstract class TrieSearch<T> {
* @param callbackParameter Optional parameter passed to the callbacks. * @param callbackParameter Optional parameter passed to the callbacks.
* @return If any pattern matched, and it's callback halted searching. * @return If any pattern matched, and it's callback halted searching.
*/ */
public boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) { public boolean matches(T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) {
return matches(textToSearch, root.getTextLength(textToSearch), startIndex, endIndex, callbackParameter); return matches(textToSearch, root.getTextLength(textToSearch), startIndex, endIndex, callbackParameter);
} }
private boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex, private boolean matches(T textToSearch, int textToSearchLength, int startIndex, int endIndex,
@Nullable Object callbackParameter) { @Nullable Object callbackParameter) {
if (endIndex > textToSearchLength) { if (endIndex > textToSearchLength) {
throw new IllegalArgumentException("endIndex: " + endIndex throw new IllegalArgumentException("endIndex: " + endIndex

View File

@@ -0,0 +1,142 @@
package app.revanced.extension.shared.settings;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceFragment;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toolbar;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
/**
* Base class for hooking activities to inject a custom PreferenceFragment with a toolbar.
* Provides common logic for initializing the activity and setting up the toolbar.
*/
@SuppressWarnings({"deprecation", "NewApi"})
public abstract class BaseActivityHook extends Activity {
/**
* Layout parameters for the toolbar, extracted from the dummy toolbar.
*/
protected static ViewGroup.LayoutParams toolbarLayoutParams;
/**
* Sets the layout parameters for the toolbar.
*/
public static void setToolbarLayoutParams(Toolbar toolbar) {
if (toolbarLayoutParams != null) {
toolbar.setLayoutParams(toolbarLayoutParams);
}
}
/**
* Initializes the activity by setting the theme, content view and injecting a PreferenceFragment.
*/
public static void initialize(BaseActivityHook hook, Activity activity) {
try {
hook.customizeActivityTheme(activity);
activity.setContentView(hook.getContentViewResourceId());
// Sanity check.
String dataString = activity.getIntent().getDataString();
if (!"revanced_settings_intent".equals(dataString)) {
Logger.printException(() -> "Unknown intent: " + dataString);
return;
}
PreferenceFragment fragment = hook.createPreferenceFragment();
hook.createToolbar(activity, fragment);
activity.getFragmentManager()
.beginTransaction()
.replace(Utils.getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
.commit();
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}
}
/**
* Creates and configures a toolbar for the activity, replacing a dummy placeholder.
*/
@SuppressLint("UseCompatLoadingForDrawables")
protected void createToolbar(Activity activity, PreferenceFragment fragment) {
// Replace dummy placeholder toolbar.
// This is required to fix submenu title alignment issue with Android ASOP 15+
ViewGroup toolBarParent = activity.findViewById(
Utils.getResourceIdentifier("revanced_toolbar_parent", "id"));
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
toolbarLayoutParams = dummyToolbar.getLayoutParams();
toolBarParent.removeView(dummyToolbar);
// Sets appropriate system navigation bar color for the activity.
ToolbarPreferenceFragment.setNavigationBarColor(activity.getWindow());
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
toolbar.setBackgroundColor(getToolbarBackgroundColor());
toolbar.setNavigationIcon(getNavigationIcon());
toolbar.setNavigationOnClickListener(getNavigationClickListener(activity));
toolbar.setTitle(Utils.getResourceIdentifier("revanced_settings_title", "string"));
final int margin = Utils.dipToPixels(16);
toolbar.setTitleMarginStart(margin);
toolbar.setTitleMarginEnd(margin);
TextView toolbarTextView = Utils.getChildView(toolbar, false, view -> view instanceof TextView);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
}
setToolbarLayoutParams(toolbar);
onPostToolbarSetup(activity, toolbar, fragment);
toolBarParent.addView(toolbar, 0);
}
/**
* Customizes the activity's theme.
*/
protected abstract void customizeActivityTheme(Activity activity);
/**
* Returns the resource ID for the content view layout.
*/
protected abstract int getContentViewResourceId();
/**
* Returns the background color for the toolbar.
*/
protected abstract int getToolbarBackgroundColor();
/**
* Returns the navigation icon drawable for the toolbar.
*/
protected abstract Drawable getNavigationIcon();
/**
* Returns the click listener for the toolbar's navigation icon.
*/
protected abstract View.OnClickListener getNavigationClickListener(Activity activity);
/**
* Creates the PreferenceFragment to be injected into the activity.
*/
protected PreferenceFragment createPreferenceFragment() {
return new ToolbarPreferenceFragment();
}
/**
* Performs additional setup after the toolbar is configured.
*
* @param activity The activity hosting the toolbar.
* @param toolbar The configured toolbar.
* @param fragment The PreferenceFragment associated with the activity.
*/
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {}
}

View File

@@ -4,9 +4,6 @@ import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE; import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.settings.Setting.parent; import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability; import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.SpoofiOSAvailability;
import app.revanced.extension.shared.spoof.ClientType;
/** /**
* Settings shared across multiple apps. * Settings shared across multiple apps.
@@ -31,9 +28,4 @@ public class BaseSettings {
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message"); public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true, "revanced_spoof_video_streams_user_dialog_message");
public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability()); public static final EnumSetting<AppLanguage> SPOOF_VIDEO_STREAMS_LANGUAGE = new EnumSetting<>("revanced_spoof_video_streams_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS)); public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true,
"revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofiOSAvailability());
// Client type must be last spoof setting due to cyclic references.
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_NO_AUTH, true, parent(SPOOF_VIDEO_STREAMS));
} }

View File

@@ -1,9 +1,8 @@
package app.revanced.extension.youtube.settings.preference; package app.revanced.extension.shared.settings.preference;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.preference.Preference; import android.preference.Preference;
import app.revanced.extension.shared.settings.preference.LogBufferManager;
/** /**
* A custom preference that clears the ReVanced debug log buffer when clicked. * A custom preference that clears the ReVanced debug log buffer when clicked.

View File

@@ -1,9 +1,8 @@
package app.revanced.extension.youtube.settings.preference; package app.revanced.extension.shared.settings.preference;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.preference.Preference; import android.preference.Preference;
import app.revanced.extension.shared.settings.preference.LogBufferManager;
/** /**
* A custom preference that triggers exporting ReVanced debug logs to the clipboard when clicked. * A custom preference that triggers exporting ReVanced debug logs to the clipboard when clicked.

View File

@@ -0,0 +1,150 @@
package app.revanced.extension.shared.settings.preference;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.graphics.Insets;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.widget.TextView;
import android.widget.Toolbar;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseActivityHook;
@SuppressWarnings({"deprecation", "NewApi"})
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
/**
* Sets toolbar for all nested preference screens.
*/
protected void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
for (int i = 0, count = parentScreen.getPreferenceCount(); i < count; i++) {
Preference childPreference = parentScreen.getPreference(i);
if (childPreference instanceof PreferenceScreen) {
// Recursively set sub preferences.
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
childPreference.setOnPreferenceClickListener(
childScreen -> {
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
.findViewById(android.R.id.content)
.getParent();
// Allow package-specific background customization.
customizeDialogBackground(rootView);
// Fix the system navigation bar color for submenus.
setNavigationBarColor(preferenceScreenDialog.getWindow());
// Fix edge-to-edge screen with Android 15 and YT 19.45+
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
// Apply padding for display cutout in landscape.
int leftPadding = cutoutInsets.left;
int rightPadding = cutoutInsets.right;
int topPadding = statusInsets.top;
int bottomPadding = navInsets.bottom;
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
return insets;
});
}
Toolbar toolbar = new Toolbar(childScreen.getContext());
toolbar.setTitle(childScreen.getTitle());
toolbar.setNavigationIcon(getBackButtonDrawable());
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
final int margin = Utils.dipToPixels(16);
toolbar.setTitleMargin(margin, 0, margin, 0);
TextView toolbarTextView = Utils.getChildView(toolbar,
true, TextView.class::isInstance);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
}
// Allow package-specific toolbar customization.
customizeToolbar(toolbar);
// Allow package-specific post-toolbar setup.
onPostToolbarSetup(toolbar, preferenceScreenDialog);
rootView.addView(toolbar, 0);
return false;
}
);
}
}
}
/**
* Sets the system navigation bar color for the activity.
* Applies the background color obtained from {@link Utils#getAppBackgroundColor()} to the navigation bar.
* For Android 10 (API 29) and above, enforces navigation bar contrast to ensure visibility.
*/
public static void setNavigationBarColor(@Nullable Window window) {
if (window == null) {
Logger.printDebug(() -> "Cannot set navigation bar color, window is null");
return;
}
window.setNavigationBarColor(Utils.getAppBackgroundColor());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.setNavigationBarContrastEnforced(true);
}
}
/**
* Returns the drawable for the back button.
*/
@SuppressLint("UseCompatLoadingForDrawables")
public static Drawable getBackButtonDrawable() {
final int backButtonResource = Utils.getResourceIdentifier(
"revanced_settings_toolbar_arrow_left", "drawable");
Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource);
customizeBackButtonDrawable(drawable);
return drawable;
}
/**
* Customizes the back button drawable.
*/
protected static void customizeBackButtonDrawable(Drawable drawable) {
drawable.setTint(Utils.getAppForegroundColor());
}
/**
* Allows subclasses to customize the dialog's root view background.
*/
protected void customizeDialogBackground(ViewGroup rootView) {
rootView.setBackgroundColor(Utils.getAppBackgroundColor());
}
/**
* Allows subclasses to customize the toolbar.
*/
protected void customizeToolbar(Toolbar toolbar) {
BaseActivityHook.setToolbarLayoutParams(toolbar);
}
/**
* Allows subclasses to perform actions after toolbar setup.
*/
protected void onPostToolbarSetup(Toolbar toolbar, Dialog preferenceScreenDialog) {}
}

View File

@@ -2,17 +2,22 @@ package app.revanced.extension.shared.spoof;
import android.os.Build; import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.BaseSettings;
@SuppressWarnings("ConstantLocale")
public enum ClientType { public enum ClientType {
/**
* Video not playable: Kids / Paid / Movie / Private / Age-restricted.
* This client can only be used when logged out.
*/
// https://dumps.tadiphone.dev/dumps/oculus/eureka // https://dumps.tadiphone.dev/dumps/oculus/eureka
ANDROID_VR_NO_AUTH( ANDROID_VR_1_61_48(
28, 28,
"ANDROID_VR", "ANDROID_VR",
"com.google.android.apps.youtube.vr.oculus", "com.google.android.apps.youtube.vr.oculus",
@@ -26,30 +31,31 @@ public enum ClientType {
"132.0.6808.3", "132.0.6808.3",
"1.61.48", "1.61.48",
false, false,
false, "Android VR 1.61"
"Android VR No auth"
), ),
// Chromecast with Google TV 4K. /**
// https://dumps.tadiphone.dev/dumps/google/kirkwood * Uses non adaptive bitrate, which fixes audio stuttering with YT Music.
ANDROID_UNPLUGGED( * Does not use AV1.
29, */
"ANDROID_UNPLUGGED", ANDROID_VR_1_43_32(
"com.google.android.apps.youtube.unplugged", ANDROID_VR_1_61_48.id,
"Google", ANDROID_VR_1_61_48.clientName,
"Google TV Streamer", Objects.requireNonNull(ANDROID_VR_1_61_48.packageName),
"Android", ANDROID_VR_1_61_48.deviceMake,
"14", ANDROID_VR_1_61_48.deviceModel,
"34", ANDROID_VR_1_61_48.osName,
"UTT3.240625.001.K5", ANDROID_VR_1_61_48.osVersion,
"132.0.6808.3", Objects.requireNonNull(ANDROID_VR_1_61_48.androidSdkVersion),
"8.49.0", Objects.requireNonNull(ANDROID_VR_1_61_48.buildId),
true, "107.0.5284.2",
true, "1.43.32",
"Android TV" ANDROID_VR_1_61_48.useAuth,
"Android VR 1.43"
), ),
// Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children". /**
// Google Pixel 9 Pro Fold * Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children".
// https://dumps.tadiphone.dev/dumps/google/barbet * <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a>
*/
ANDROID_CREATOR( ANDROID_CREATOR(
14, 14,
"ANDROID_CREATOR", "ANDROID_CREATOR",
@@ -63,45 +69,47 @@ public enum ClientType {
"132.0.6779.0", "132.0.6779.0",
"23.47.101", "23.47.101",
true, true,
true, "Android Studio"
"Android Creator"
), ),
IOS_UNPLUGGED( /**
33, * Internal YT client for an unreleased YT client. May stop working at any time.
"IOS_UNPLUGGED", */
"com.google.ios.youtubeunplugged", VISIONOS(101,
"VISIONOS",
"Apple", "Apple",
forceAVC() "RealityDevice14,1",
// 11 Pro Max (last device with iOS 13) "visionOS",
? "iPhone12,5" "1.3.21O771",
// 15 Pro Max "0.1",
: "iPhone16,2", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
"iOS", false,
forceAVC() "visionOS"
// iOS 13 and earlier uses only AVC. 14+ adds VP9 and AV1. ),
? "13.7.17H35" /**
: "18.2.22C152", * The device machine id for the iPad 6th Gen (iPad7,6).
null, * AV1 hardware decoding is not supported.
null, * See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
null, *
// Version number should be a valid iOS release. * Based on Google's actions to date, PoToken may not be required on devices with very low specs.
// https://www.ipa4fun.com/history/152043/ * For example, suppose the User-Agent for a PlayStation 3 (with 256MB of RAM) is used.
forceAVC() * Accessing 'Web' (https://www.youtube.com) will redirect to 'TV' (https://www.youtube.com/tv).
// Some newer versions can also force AVC, * 'TV' target devices with very low specs, such as embedded devices, game consoles, and blu-ray players, so PoToken is not required.
// but 6.45 is the last version that supports iOS 13. *
? "6.45" * For this reason, the device machine id for the iPad 6th Gen (with 2GB of RAM),
: "8.49", * the lowest spec device capable of running iPadOS 17, was used.
true, */
true, IPADOS(5,
forceAVC() "IOS",
? "iOS TV Force AVC" "Apple",
: "iOS TV" "iPad7,6",
"iPadOS",
"17.7.10.21H450",
"19.22.3",
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
false,
"iPadOS"
); );
private static boolean forceAVC() {
return BaseSettings.SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC.get();
}
/** /**
* YouTube * YouTube
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a> * <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
@@ -113,6 +121,7 @@ public enum ClientType {
/** /**
* App package name. * App package name.
*/ */
@Nullable
private final String packageName; private final String packageName;
/** /**
@@ -166,12 +175,6 @@ public enum ClientType {
*/ */
public final String clientVersion; public final String clientVersion;
/**
* If this client requires authentication and does not work
* if logged out or in incognito mode.
*/
public final boolean requiresAuth;
/** /**
* If the client should use authentication if available. * If the client should use authentication if available.
*/ */
@@ -182,19 +185,20 @@ public enum ClientType {
*/ */
public final String friendlyName; public final String friendlyName;
@SuppressWarnings("ConstantLocale") /**
* Android constructor.
*/
ClientType(int id, ClientType(int id,
String clientName, String clientName,
String packageName, @NonNull String packageName,
String deviceMake, String deviceMake,
String deviceModel, String deviceModel,
String osName, String osName,
String osVersion, String osVersion,
@Nullable String androidSdkVersion, @NonNull String androidSdkVersion,
@Nullable String buildId, @NonNull String buildId,
@Nullable String cronetVersion, @NonNull String cronetVersion,
String clientVersion, String clientVersion,
boolean requiresAuth,
boolean useAuth, boolean useAuth,
String friendlyName) { String friendlyName) {
this.id = id; this.id = id;
@@ -208,36 +212,46 @@ public enum ClientType {
this.buildId = buildId; this.buildId = buildId;
this.cronetVersion = cronetVersion; this.cronetVersion = cronetVersion;
this.clientVersion = clientVersion; this.clientVersion = clientVersion;
this.requiresAuth = requiresAuth;
this.useAuth = useAuth; this.useAuth = useAuth;
this.friendlyName = friendlyName; this.friendlyName = friendlyName;
Locale defaultLocale = Locale.getDefault(); Locale defaultLocale = Locale.getDefault();
if (androidSdkVersion == null) { this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s; %s; Build/%s; Cronet/%s)",
// Convert version from '18.2.22C152' into '18_2_22' packageName,
String userAgentOsVersion = osVersion clientVersion,
.replaceAll("(\\d+\\.\\d+\\.\\d+).*", "$1") osVersion,
.replace(".", "_"); defaultLocale,
// https://github.com/mitmproxy/mitmproxy/issues/4836 deviceModel,
this.userAgent = String.format("%s/%s (%s; U; CPU iOS %s like Mac OS X; %s)", Objects.requireNonNull(buildId),
packageName, Objects.requireNonNull(cronetVersion)
clientVersion, );
deviceModel,
userAgentOsVersion,
defaultLocale
);
} else {
this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s; %s; Build/%s; Cronet/%s)",
packageName,
clientVersion,
osVersion,
defaultLocale,
deviceModel,
Objects.requireNonNull(buildId),
Objects.requireNonNull(cronetVersion)
);
}
Logger.printDebug(() -> "userAgent: " + this.userAgent); Logger.printDebug(() -> "userAgent: " + this.userAgent);
} }
@SuppressWarnings("ConstantLocale")
ClientType(int id,
String clientName,
String deviceMake,
String deviceModel,
String osName,
String osVersion,
String clientVersion,
String userAgent,
boolean useAuth,
String friendlyName) {
this.id = id;
this.clientName = clientName;
this.deviceMake = deviceMake;
this.deviceModel = deviceModel;
this.osName = osName;
this.osVersion = osVersion;
this.clientVersion = clientVersion;
this.userAgent = userAgent;
this.useAuth = useAuth;
this.friendlyName = friendlyName;
this.packageName = null;
this.androidSdkVersion = null;
this.buildId = null;
this.cronetVersion = null;
}
} }

View File

@@ -6,38 +6,70 @@ import android.text.TextUtils;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest; import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class SpoofVideoStreamsPatch { public class SpoofVideoStreamsPatch {
/**
* Domain used for internet connectivity verification.
* It has an empty response body and is only used to check for a 204 response code.
* <p>
* If an unreachable IP address (127.0.0.1) is used, no response code is provided.
* <p>
* YouTube handles unreachable IP addresses without issue.
* YouTube Music has an issue with waiting for the Cronet connect timeout of 30s on mobile networks.
* <p>
* Using a VPN or DNS can temporarily resolve this issue,
* But the ideal workaround is to avoid using an unreachable IP address.
*/
private static final String INTERNET_CONNECTION_CHECK_URI_STRING = "https://www.google.com/gen_204";
private static final Uri INTERNET_CONNECTION_CHECK_URI = Uri.parse(INTERNET_CONNECTION_CHECK_URI_STRING);
private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_VIDEO_STREAMS.get(); private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_VIDEO_STREAMS.get();
private static final boolean FIX_HLS_CURRENT_TIME = SPOOF_STREAMING_DATA @Nullable
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED; private static volatile AppLanguage languageOverride;
/** private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_61_48;
* Any unreachable ip address. Used to intentionally fail requests.
*/
private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0";
private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING);
/** /**
* @return If this patch was included during patching. * @return If this patch was included during patching.
*/ */
private static boolean isPatchIncluded() { public static boolean isPatchIncluded() {
return false; // Modified during patching. return false; // Modified during patching.
} }
public static boolean notSpoofingToAndroid() { @Nullable
return !isPatchIncluded() public static AppLanguage getLanguageOverride() {
|| !BaseSettings.SPOOF_VIDEO_STREAMS.get() return languageOverride;
|| BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED; }
/**
* @param language Language override for non-authenticated requests. If this is null then
* {@link BaseSettings#SPOOF_VIDEO_STREAMS_LANGUAGE} is used.
*/
public static void setLanguageOverride(@Nullable AppLanguage language) {
languageOverride = language;
}
public static void setClientsToUse(List<ClientType> availableClients, ClientType client) {
preferredClient = Objects.requireNonNull(client);
StreamingDataRequest.setClientOrderToUse(availableClients, client);
}
public static boolean spoofingToClientWithNoMultiAudioStreams() {
return isPatchIncluded()
&& SPOOF_STREAMING_DATA
&& preferredClient != ClientType.IPADOS;
} }
/** /**
@@ -53,9 +85,9 @@ public class SpoofVideoStreamsPatch {
String path = playerRequestUri.getPath(); String path = playerRequestUri.getPath();
if (path != null && path.contains("get_watch")) { if (path != null && path.contains("get_watch")) {
Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri"); Logger.printDebug(() -> "Blocking 'get_watch' by returning internet connection check uri");
return UNREACHABLE_HOST_URI; return INTERNET_CONNECTION_CHECK_URI;
} }
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "blockGetWatchRequest failure", ex); Logger.printException(() -> "blockGetWatchRequest failure", ex);
@@ -77,9 +109,9 @@ public class SpoofVideoStreamsPatch {
String path = originalUri.getPath(); String path = originalUri.getPath();
if (path != null && path.contains("initplayback")) { if (path != null && path.contains("initplayback")) {
Logger.printDebug(() -> "Blocking 'initplayback' by clearing query"); Logger.printDebug(() -> "Blocking 'initplayback' by returning internet connection check uri");
return originalUri.buildUpon().clearQuery().build().toString(); return INTERNET_CONNECTION_CHECK_URI_STRING;
} }
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "blockInitPlaybackRequest failure", ex); Logger.printException(() -> "blockInitPlaybackRequest failure", ex);
@@ -252,16 +284,7 @@ public class SpoofVideoStreamsPatch {
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability { public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return BaseSettings.SPOOF_VIDEO_STREAMS.get() return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_NO_AUTH;
}
}
public static final class SpoofiOSAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
return BaseSettings.SPOOF_VIDEO_STREAMS.get()
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED;
} }
} }
} }

View File

@@ -1,5 +1,7 @@
package app.revanced.extension.shared.spoof.requests; package app.revanced.extension.shared.spoof.requests;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -10,8 +12,10 @@ import java.util.Locale;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.requests.Requester; import app.revanced.extension.shared.requests.Requester;
import app.revanced.extension.shared.requests.Route; import app.revanced.extension.shared.requests.Route;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
final class PlayerRoutes { final class PlayerRoutes {
static final Route.CompiledRoute GET_STREAMING_DATA = new Route( static final Route.CompiledRoute GET_STREAMING_DATA = new Route(
@@ -37,14 +41,16 @@ final class PlayerRoutes {
try { try {
JSONObject context = new JSONObject(); JSONObject context = new JSONObject();
// Can override default language only if no login is used. AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride();
// Could use preferred audio for all clients that do not login, if (language == null || clientType == ANDROID_VR_1_43_32) {
// but if this is a fall over client it will set the language even though // Force original audio has not overrode the language.
// the audio language is not selectable in the UI. // Or if YT has fallen over to the last unauthenticated client (VR 1.43), then
ClientType userSelectedClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); // always use the app language because forcing an audio stream of specific languages
Locale streamLocale = userSelectedClient == ClientType.ANDROID_VR_NO_AUTH // can sometimes fail so it's better to try and load something rather than nothing.
? BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get().getLocale() language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get();
: Locale.getDefault(); }
//noinspection ExtractMethodRecommender
Locale streamLocale = language.getLocale();
JSONObject client = new JSONObject(); JSONObject client = new JSONObject();
client.put("deviceMake", clientType.deviceMake); client.put("deviceMake", clientType.deviceMake);

View File

@@ -1,5 +1,6 @@
package app.revanced.extension.shared.spoof.requests; package app.revanced.extension.shared.spoof.requests;
import static app.revanced.extension.shared.ByteTrieSearch.convertStringsToBytes;
import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA; import static app.revanced.extension.shared.spoof.requests.PlayerRoutes.GET_STREAMING_DATA;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -13,12 +14,18 @@ import java.net.HttpURLConnection;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
@@ -35,21 +42,27 @@ import app.revanced.extension.shared.spoof.ClientType;
*/ */
public class StreamingDataRequest { public class StreamingDataRequest {
private static final ClientType[] CLIENT_ORDER_TO_USE; private static volatile ClientType[] clientOrderToUse = ClientType.values();
static { public static void setClientOrderToUse(List<ClientType> availableClients, ClientType preferredClient) {
ClientType[] allClientTypes = ClientType.values(); Objects.requireNonNull(preferredClient);
ClientType preferredClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length]; int availableClientSize = availableClients.size();
CLIENT_ORDER_TO_USE[0] = preferredClient; if (!availableClients.contains(preferredClient)) {
availableClientSize++;
}
clientOrderToUse = new ClientType[availableClientSize];
clientOrderToUse[0] = preferredClient;
int i = 1; int i = 1;
for (ClientType c : allClientTypes) { for (ClientType c : availableClients) {
if (c != preferredClient) { if (c != preferredClient) {
CLIENT_ORDER_TO_USE[i++] = c; clientOrderToUse[i++] = c;
} }
} }
Logger.printDebug(() -> "Available spoof clients: " + Arrays.toString(clientOrderToUse));
} }
private static final String AUTHORIZATION_HEADER = "Authorization"; private static final String AUTHORIZATION_HEADER = "Authorization";
@@ -87,6 +100,16 @@ public class StreamingDataRequest {
} }
}); });
/**
* Strings found in the response if the video is a livestream.
*/
private static final ByteTrieSearch liveStreamBufferSearch = new ByteTrieSearch(
convertStringsToBytes(
"yt_live_broadcast",
"yt_premiere_broadcast"
)
);
private static volatile ClientType lastSpoofedClientType; private static volatile ClientType lastSpoofedClientType;
public static String getLastSpoofedClientName() { public static String getLastSpoofedClientName() {
@@ -154,7 +177,7 @@ public class StreamingDataRequest {
} }
} }
if (!authHeadersIncludes && clientType.requiresAuth) { if (!authHeadersIncludes && clientType.useAuth) {
Logger.printDebug(() -> "Skipping client since user is not logged in: " + clientType Logger.printDebug(() -> "Skipping client since user is not logged in: " + clientType
+ " videoId: " + videoId); + " videoId: " + videoId);
return null; return null;
@@ -193,9 +216,9 @@ public class StreamingDataRequest {
// Retry with different client if empty response body is received. // Retry with different client if empty response body is received.
int i = 0; int i = 0;
for (ClientType clientType : CLIENT_ORDER_TO_USE) { for (ClientType clientType : clientOrderToUse) {
// Show an error if the last client type fails, or if debug is enabled then show for all attempts. // Show an error if the last client type fails, or if debug is enabled then show for all attempts.
final boolean showErrorToast = (++i == CLIENT_ORDER_TO_USE.length) || debugEnabled; final boolean showErrorToast = (++i == clientOrderToUse.length) || debugEnabled;
HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast); HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast);
if (connection != null) { if (connection != null) {
@@ -215,9 +238,13 @@ public class StreamingDataRequest {
while ((bytesRead = inputStream.read(buffer)) >= 0) { while ((bytesRead = inputStream.read(buffer)) >= 0) {
baos.write(buffer, 0, bytesRead); baos.write(buffer, 0, bytesRead);
} }
lastSpoofedClientType = clientType; if (clientType == ClientType.ANDROID_CREATOR && liveStreamBufferSearch.matches(buffer)) {
Logger.printDebug(() -> "Skipping Android Studio as video is a livestream: " + videoId);
} else {
lastSpoofedClientType = clientType;
return ByteBuffer.wrap(baos.toByteArray()); return ByteBuffer.wrap(baos.toByteArray());
}
} }
} }
} catch (IOException ex) { } catch (IOException ex) {

View File

@@ -1,7 +1,7 @@
package app.revanced.extension.youtube.patches; package app.revanced.extension.youtube.patches;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch; import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
@@ -11,16 +11,21 @@ public class ForceOriginalAudioPatch {
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4"; private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
/** /**
* If the conditions to use this patch were present when the app launched. * Injection point.
*/ */
public static boolean PATCH_AVAILABLE = SpoofVideoStreamsPatch.notSpoofingToAndroid(); public static void setPreferredLanguage() {
if (Settings.FORCE_ORIGINAL_AUDIO.get()
public static final class ForceOriginalAudioAvailability implements Setting.Availability { && SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
@Override // If client spoofing does not use authentication and lacks multi-audio streams,
public boolean isAvailable() { // then can use any language code for the request and if that requested language is
// Check conditions of launch and now. Otherwise if spoofing is changed // not available YT uses the original audio language. Authenticated requests ignore
// without a restart the setting will show as available when it's not. // the language code and always use the account language. Use a language that is
return PATCH_AVAILABLE && SpoofVideoStreamsPatch.notSpoofingToAndroid(); // not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
// but the language is also supported natively by the Meta Quest device that
// Android VR is spoofing.
AppLanguage override = AppLanguage.SV;
Logger.printDebug(() -> "Setting language override: " + override);
SpoofVideoStreamsPatch.setLanguageOverride(override);
} }
} }

View File

@@ -10,7 +10,7 @@ import java.util.List;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.StringTrieSearch; import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")

View File

@@ -74,6 +74,10 @@ final class ButtonsFilter extends Filter {
Settings.HIDE_ASK_BUTTON, Settings.HIDE_ASK_BUTTON,
"yt_fill_spark" "yt_fill_spark"
), ),
new ByteArrayFilterGroup(
Settings.HIDE_SHOP_BUTTON,
"yt_outline_bag"
),
new ByteArrayFilterGroup( new ByteArrayFilterGroup(
Settings.HIDE_STOP_ADS_BUTTON, Settings.HIDE_STOP_ADS_BUTTON,
"yt_outline_slash_circle_left" "yt_outline_slash_circle_left"

View File

@@ -14,7 +14,7 @@ import java.util.regex.Pattern;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.ByteTrieSearch; import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
/** /**

View File

@@ -1,6 +1,6 @@
package app.revanced.extension.youtube.patches.components; package app.revanced.extension.youtube.patches.components;
import app.revanced.extension.youtube.StringTrieSearch; import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType; import app.revanced.extension.youtube.shared.PlayerType;

View File

@@ -4,7 +4,7 @@ import androidx.annotation.NonNull;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.BooleanSetting; import app.revanced.extension.shared.settings.BooleanSetting;
import app.revanced.extension.youtube.ByteTrieSearch; import app.revanced.extension.shared.ByteTrieSearch;
abstract class FilterGroup<T> { abstract class FilterGroup<T> {
final static class FilterGroupResult { final static class FilterGroupResult {

View File

@@ -5,9 +5,9 @@ import androidx.annotation.NonNull;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import app.revanced.extension.youtube.ByteTrieSearch; import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.youtube.StringTrieSearch; import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.TrieSearch; import app.revanced.extension.shared.TrieSearch;
abstract class FilterGroupList<V, T extends FilterGroup<V>> implements Iterable<T> { abstract class FilterGroupList<V, T extends FilterGroup<V>> implements Iterable<T> {

View File

@@ -14,9 +14,9 @@ import java.util.concurrent.atomic.AtomicReference;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.ByteTrieSearch; import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.youtube.StringTrieSearch; import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.TrieSearch; import app.revanced.extension.shared.TrieSearch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar; import app.revanced.extension.youtube.shared.NavigationBar;
import app.revanced.extension.youtube.shared.PlayerType; import app.revanced.extension.youtube.shared.PlayerType;

View File

@@ -10,7 +10,7 @@ import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.StringTrieSearch; import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.patches.ChangeHeaderPatch; import app.revanced.extension.youtube.patches.ChangeHeaderPatch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar; import app.revanced.extension.youtube.shared.NavigationBar;

View File

@@ -8,7 +8,7 @@ import java.util.List;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.StringTrieSearch; import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")

View File

@@ -9,13 +9,13 @@ import app.revanced.extension.youtube.shared.ShortsPlayerState;
public class PlayerFlyoutMenuItemsFilter extends Filter { public class PlayerFlyoutMenuItemsFilter extends Filter {
public static final class HideAudioFlyoutMenuAvailability implements Setting.Availability { public static final class HideAudioFlyoutMenuAvailability implements Setting.Availability {
private static final boolean AVAILABLE_ON_LAUNCH = SpoofVideoStreamsPatch.notSpoofingToAndroid(); private static final boolean AVAILABLE_ON_LAUNCH = !SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams();
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
// Check conditions of launch and now. Otherwise if spoofing is changed // Check conditions of launch and now. Otherwise if spoofing is changed
// without a restart the setting will show as available when it's not. // without a restart the setting will show as available when it's not.
return AVAILABLE_ON_LAUNCH && SpoofVideoStreamsPatch.notSpoofingToAndroid(); return AVAILABLE_ON_LAUNCH && !SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams();
} }
} }

View File

@@ -12,7 +12,7 @@ import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch;
import app.revanced.extension.youtube.patches.VideoInformation; import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.youtube.TrieSearch; import app.revanced.extension.shared.TrieSearch;
/** /**
* Searches for video id's in the proto buffer of Shorts dislike. * Searches for video id's in the proto buffer of Shorts dislike.

View File

@@ -0,0 +1,32 @@
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_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;
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
import java.util.List;
import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class SpoofVideoStreamsPatch {
/**
* Injection point.
*/
public static void setClientOrderToUse() {
List<ClientType> availableClients = List.of(
ANDROID_VR_1_61_48,
VISIONOS,
ANDROID_CREATOR,
ANDROID_VR_1_43_32,
IPADOS
);
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
availableClients, Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
}
}

View File

@@ -1,50 +1,120 @@
package app.revanced.extension.youtube.settings; package app.revanced.extension.youtube.settings;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.util.TypedValue; import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toolbar; import android.widget.Toolbar;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.AppLanguage; import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseActivityHook;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.patches.VersionCheckPatch; import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch; import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment; import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
/** /**
* Hooks LicenseActivity. * Hooks LicenseActivity to inject a custom ReVancedPreferenceFragment with a toolbar and search functionality.
* <p>
* This class is responsible for injecting our own fragment by replacing the LicenseActivity.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("deprecation")
public class LicenseActivityHook extends Activity { public class LicenseActivityHook extends BaseActivityHook {
private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value. private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value.
private static ViewGroup.LayoutParams toolbarLayoutParams; /**
* Controller for managing search view components in the toolbar.
*/
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
public static SearchViewController searchViewController; public static SearchViewController searchViewController;
public static void setToolbarLayoutParams(Toolbar toolbar) { /**
if (toolbarLayoutParams != null) { * Injection point
toolbar.setLayoutParams(toolbarLayoutParams); * <p>
* Creates an instance of LicenseActivityHook for use in static initialization.
*/
@SuppressWarnings("unused")
public static LicenseActivityHook createInstance() {
return new LicenseActivityHook();
}
/**
* Customizes the activity theme based on dark/light mode.
*/
@Override
protected void customizeActivityTheme(Activity activity) {
final var theme = Utils.isDarkModeEnabled()
? "Theme.YouTube.Settings.Dark"
: "Theme.YouTube.Settings";
activity.setTheme(Utils.getResourceIdentifier(theme, "style"));
}
/**
* Returns the resource ID for the YouTube settings layout.
*/
@Override
protected int getContentViewResourceId() {
return Utils.getResourceIdentifier("revanced_settings_with_toolbar", "layout");
}
/**
* Returns the toolbar background color based on dark/light mode.
*/
@Override
protected int getToolbarBackgroundColor() {
final String colorName = Utils.isDarkModeEnabled()
? "yt_black3"
: "yt_white1";
return Utils.getColorFromString(colorName);
}
/**
* Returns the navigation icon drawable for the toolbar.
*/
@Override
protected Drawable getNavigationIcon() {
return ReVancedPreferenceFragment.getBackButtonDrawable();
}
/**
* Returns the click listener for the navigation icon.
*/
@Override
protected View.OnClickListener getNavigationClickListener(Activity activity) {
return null;
}
/**
* Adds search view components to the toolbar for ReVancedPreferenceFragment.
*
* @param activity The activity hosting the toolbar.
* @param toolbar The configured toolbar.
* @param fragment The PreferenceFragment associated with the activity.
*/
@Override
protected void onPostToolbarSetup(Activity activity, Toolbar toolbar, PreferenceFragment fragment) {
if (fragment instanceof ReVancedPreferenceFragment) {
searchViewController = SearchViewController.addSearchViewComponents(
activity, toolbar, (ReVancedPreferenceFragment) fragment);
} }
} }
/**
* Creates a new ReVancedPreferenceFragment for the activity.
*/
@Override
protected PreferenceFragment createPreferenceFragment() {
return new ReVancedPreferenceFragment();
}
/** /**
* Injection point. * Injection point.
* Overrides the ReVanced settings language. * Overrides the ReVanced settings language.
*/ */
@SuppressWarnings("unused")
public static Context getAttachBaseContext(Context original) { public static Context getAttachBaseContext(Context original) {
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get(); AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
if (language == AppLanguage.DEFAULT) { if (language == AppLanguage.DEFAULT) {
@@ -57,6 +127,7 @@ public class LicenseActivityHook extends Activity {
/** /**
* Injection point. * Injection point.
*/ */
@SuppressWarnings("unused")
public static boolean useCairoSettingsFragment(boolean original) { public static boolean useCairoSettingsFragment(boolean original) {
// Early targets have layout issues and it's better to always force off. // Early targets have layout issues and it's better to always force off.
if (!VersionCheckPatch.IS_19_34_OR_GREATER) { if (!VersionCheckPatch.IS_19_34_OR_GREATER) {
@@ -80,87 +151,6 @@ public class LicenseActivityHook extends Activity {
/** /**
* Injection point. * Injection point.
* <p> * <p>
* Hooks LicenseActivity#onCreate in order to inject our own fragment.
*/
public static void initialize(Activity licenseActivity) {
try {
setActivityTheme(licenseActivity);
ReVancedPreferenceFragment.setNavigationBarColor(licenseActivity.getWindow());
licenseActivity.setContentView(getResourceIdentifier(
"revanced_settings_with_toolbar", "layout"));
// Sanity check.
String dataString = licenseActivity.getIntent().getDataString();
if (!"revanced_settings_intent".equals(dataString)) {
Logger.printException(() -> "Unknown intent: " + dataString);
return;
}
PreferenceFragment fragment = new ReVancedPreferenceFragment();
createToolbar(licenseActivity, fragment);
//noinspection deprecation
licenseActivity.getFragmentManager()
.beginTransaction()
.replace(getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
.commit();
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}
}
@SuppressLint("UseCompatLoadingForDrawables")
private static void createToolbar(Activity activity, PreferenceFragment fragment) {
// Replace dummy placeholder toolbar.
// This is required to fix submenu title alignment issue with Android ASOP 15+
ViewGroup toolBarParent = activity.findViewById(
getResourceIdentifier("revanced_toolbar_parent", "id"));
ViewGroup dummyToolbar = Utils.getChildViewByResourceName(toolBarParent, "revanced_toolbar");
toolbarLayoutParams = dummyToolbar.getLayoutParams();
toolBarParent.removeView(dummyToolbar);
Toolbar toolbar = new Toolbar(toolBarParent.getContext());
toolbar.setBackgroundColor(getToolbarBackgroundColor());
toolbar.setNavigationIcon(ReVancedPreferenceFragment.getBackButtonDrawable());
toolbar.setTitle(getResourceIdentifier("revanced_settings_title", "string"));
final int margin = Utils.dipToPixels(16);
toolbar.setTitleMarginStart(margin);
toolbar.setTitleMarginEnd(margin);
TextView toolbarTextView = Utils.getChildView(toolbar, false,
view -> view instanceof TextView);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
}
setToolbarLayoutParams(toolbar);
// Add Search bar only for ReVancedPreferenceFragment.
if (fragment instanceof ReVancedPreferenceFragment) {
searchViewController = SearchViewController.addSearchViewComponents(activity, toolbar, (ReVancedPreferenceFragment) fragment);
}
toolBarParent.addView(toolbar, 0);
}
public static void setActivityTheme(Activity activity) {
final var theme = Utils.isDarkModeEnabled()
? "Theme.YouTube.Settings.Dark"
: "Theme.YouTube.Settings";
activity.setTheme(getResourceIdentifier(theme, "style"));
}
public static int getToolbarBackgroundColor() {
final String colorName = Utils.isDarkModeEnabled()
? "yt_black3"
: "yt_white1";
return Utils.getColorFromString(colorName);
}
/**
* Injection point.
*
* Updates dark/light mode since YT settings can force light/dark mode * Updates dark/light mode since YT settings can force light/dark mode
* which can differ from the global device settings. * which can differ from the global device settings.
*/ */
@@ -173,6 +163,10 @@ public class LicenseActivityHook extends Activity {
} }
} }
/**
* Handles configuration changes, such as orientation, to update the search view.
*/
@SuppressWarnings("unused")
public static void handleConfigurationChanged(Activity activity, Configuration newConfig) { public static void handleConfigurationChanged(Activity activity, Configuration newConfig) {
if (searchViewController != null) { if (searchViewController != null) {
searchViewController.handleOrientationChange(newConfig.orientation); searchViewController.handleOrientationChange(newConfig.orientation);

View File

@@ -12,7 +12,6 @@ import static app.revanced.extension.youtube.patches.ChangeHeaderPatch.HeaderLog
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.ChangeStartPageTypeAvailability; import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.ChangeStartPageTypeAvailability;
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage; import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode; import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode;
import static app.revanced.extension.youtube.patches.ForceOriginalAudioPatch.ForceOriginalAudioAvailability;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
@@ -42,6 +41,7 @@ import app.revanced.extension.shared.settings.LongSetting;
import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.settings.StringSetting; import app.revanced.extension.shared.settings.StringSetting;
import app.revanced.extension.shared.settings.preference.SharedPrefCategory; import app.revanced.extension.shared.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.DeArrowAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
@@ -75,7 +75,7 @@ public class Settings extends BaseSettings {
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true); "0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);
// Audio // Audio
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, new ForceOriginalAudioAvailability()); public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
// Ads // Ads
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE); public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
@@ -230,6 +230,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE); public static final BooleanSetting HIDE_REPORT_BUTTON = new BooleanSetting("revanced_hide_report_button", FALSE);
public static final BooleanSetting HIDE_SAVE_BUTTON = new BooleanSetting("revanced_hide_save_button", FALSE); public static final BooleanSetting HIDE_SAVE_BUTTON = new BooleanSetting("revanced_hide_save_button", FALSE);
public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE); public static final BooleanSetting HIDE_SHARE_BUTTON = new BooleanSetting("revanced_hide_share_button", FALSE);
public static final BooleanSetting HIDE_SHOP_BUTTON = new BooleanSetting("revanced_hide_shop_button", FALSE);
public static final BooleanSetting HIDE_STOP_ADS_BUTTON = new BooleanSetting("revanced_hide_stop_ads_button", TRUE); public static final BooleanSetting HIDE_STOP_ADS_BUTTON = new BooleanSetting("revanced_hide_stop_ads_button", TRUE);
public static final BooleanSetting HIDE_THANKS_BUTTON = new BooleanSetting("revanced_hide_thanks_button", TRUE); public static final BooleanSetting HIDE_THANKS_BUTTON = new BooleanSetting("revanced_hide_thanks_button", TRUE);
@@ -357,6 +358,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE); public static final BooleanSetting REMOVE_TRACKING_QUERY_PARAMETER = new BooleanSetting("revanced_remove_tracking_query_parameter", TRUE);
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true, public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
"revanced_spoof_device_dimensions_user_dialog_message"); "revanced_spoof_device_dimensions_user_dialog_message");
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false, public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG)); "revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));

View File

@@ -6,18 +6,26 @@ import android.content.Context;
import android.preference.SwitchPreference; import android.preference.SwitchPreference;
import android.util.AttributeSet; import android.util.AttributeSet;
import app.revanced.extension.youtube.patches.ForceOriginalAudioPatch; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings({"deprecation", "unused"}) @SuppressWarnings({"deprecation", "unused"})
public class ForceOriginalAudioSwitchPreference extends SwitchPreference { public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|| !(Settings.SPOOF_VIDEO_STREAMS.get()
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR);
{ {
if (!ForceOriginalAudioPatch.PATCH_AVAILABLE) { if (!available) {
// Show why force audio is not available. // Show why force audio is not available.
String summary = str("revanced_force_original_audio_not_available"); String summary = str("revanced_force_original_audio_not_available");
setSummary(summary); super.setSummary(summary);
setSummaryOn(summary); super.setSummaryOn(summary);
setSummaryOff(summary); super.setSummaryOff(summary);
super.setEnabled(false);
} }
} }
@@ -33,4 +41,23 @@ public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
public ForceOriginalAudioSwitchPreference(Context context) { public ForceOriginalAudioSwitchPreference(Context context) {
super(context); super(context);
} }
@Override
public void setEnabled(boolean enabled) {
if (!available) {
return;
}
super.setEnabled(enabled);
}
@Override
public void setSummary(CharSequence summary) {
if (!available) {
return;
}
super.setSummary(summary);
}
} }

View File

@@ -12,8 +12,8 @@ import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
public class HideAudioFlyoutMenuPreference extends SwitchPreference { public class HideAudioFlyoutMenuPreference extends SwitchPreference {
{ {
// Audio menu is not available if spoofing to Android client type. // Audio menu is not available if spoofing to most client types.
if (!SpoofVideoStreamsPatch.notSpoofingToAndroid()) { if (SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
String summary = str("revanced_hide_player_flyout_audio_track_not_available"); String summary = str("revanced_hide_player_flyout_audio_track_not_available");
setSummary(summary); setSummary(summary);
setSummaryOn(summary); setSummaryOn(summary);

View File

@@ -3,11 +3,7 @@ package app.revanced.extension.youtube.settings.preference;
import static app.revanced.extension.shared.StringRef.str; import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.getResourceIdentifier; import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import android.annotation.SuppressLint;
import android.app.Dialog; import android.app.Dialog;
import android.graphics.Insets;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceCategory; import android.preference.PreferenceCategory;
@@ -17,11 +13,6 @@ import android.preference.SwitchPreference;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.BackgroundColorSpan; import android.text.style.BackgroundColorSpan;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsets;
import android.widget.TextView;
import android.widget.Toolbar; import android.widget.Toolbar;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
@@ -40,16 +31,16 @@ import java.util.regex.Pattern;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment;
import app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory; import app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory;
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
import app.revanced.extension.youtube.settings.LicenseActivityHook; import app.revanced.extension.youtube.settings.LicenseActivityHook;
import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup; import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup;
/** /**
* Preference fragment for ReVanced settings. * Preference fragment for ReVanced settings.
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings({"deprecation", "NewApi"})
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment { public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
/** /**
* The main PreferenceScreen used to display the current set of preferences. * The main PreferenceScreen used to display the current set of preferences.
@@ -70,31 +61,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
*/ */
private final List<AbstractPreferenceSearchData<?>> allPreferences = new ArrayList<>(); private final List<AbstractPreferenceSearchData<?>> allPreferences = new ArrayList<>();
@SuppressLint("UseCompatLoadingForDrawables")
public static Drawable getBackButtonDrawable() {
final int backButtonResource = getResourceIdentifier("revanced_settings_toolbar_arrow_left", "drawable");
Drawable drawable = Utils.getContext().getResources().getDrawable(backButtonResource);
drawable.setTint(Utils.getAppForegroundColor());
return drawable;
}
/**
* Sets the system navigation bar color for the activity.
* Applies the background color obtained from {@link Utils#getAppBackgroundColor()} to the navigation bar.
* For Android 10 (API 29) and above, enforces navigation bar contrast to ensure visibility.
*/
public static void setNavigationBarColor(@Nullable Window window) {
if (window == null) {
Logger.printDebug(() -> "Cannot set navigation bar color, window is null");
return;
}
window.setNavigationBarColor(Utils.getAppBackgroundColor());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.setNavigationBarContrastEnforced(true);
}
}
/** /**
* Initializes the preference fragment, copying the original screen to allow full restoration. * Initializes the preference fragment, copying the original screen to allow full restoration.
*/ */
@@ -139,8 +105,28 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
} }
} }
/**
* Sets toolbar for all nested preference screens.
*/
@Override
protected void customizeToolbar(Toolbar toolbar) {
LicenseActivityHook.setToolbarLayoutParams(toolbar);
}
/**
* Perform actions after toolbar setup.
*/
@Override
protected void onPostToolbarSetup(Toolbar toolbar, Dialog preferenceScreenDialog) {
if (LicenseActivityHook.searchViewController != null
&& LicenseActivityHook.searchViewController.isSearchActive()) {
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
}
}
/** /**
* Recursively collects all preferences from the screen or group. * Recursively collects all preferences from the screen or group.
*
* @param includeDepth Menu depth to start including preferences. * @param includeDepth Menu depth to start including preferences.
* A value of 0 adds all preferences. * A value of 0 adds all preferences.
*/ */
@@ -222,75 +208,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
preferenceScreen.addPreference(noResultsPreference); preferenceScreen.addPreference(noResultsPreference);
} }
} }
/**
* Sets toolbar for all nested preference screens.
*/
private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
for (int i = 0, count = parentScreen.getPreferenceCount(); i < count; i++) {
Preference childPreference = parentScreen.getPreference(i);
if (childPreference instanceof PreferenceScreen) {
// Recursively set sub preferences.
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
childPreference.setOnPreferenceClickListener(
childScreen -> {
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
.findViewById(android.R.id.content)
.getParent();
// Fix the system navigation bar color for submenus.
setNavigationBarColor(preferenceScreenDialog.getWindow());
// Fix edge-to-edge screen with Android 15 and YT 19.45+
// https://developer.android.com/develop/ui/views/layout/edge-to-edge#system-bars-insets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
rootView.setOnApplyWindowInsetsListener((v, insets) -> {
Insets statusInsets = insets.getInsets(WindowInsets.Type.statusBars());
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
Insets cutoutInsets = insets.getInsets(WindowInsets.Type.displayCutout());
// Apply padding for display cutout in landscape.
int leftPadding = cutoutInsets.left;
int rightPadding = cutoutInsets.right;
int topPadding = statusInsets.top;
int bottomPadding = navInsets.bottom;
v.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
return insets;
});
}
Toolbar toolbar = new Toolbar(childScreen.getContext());
toolbar.setTitle(childScreen.getTitle());
toolbar.setNavigationIcon(getBackButtonDrawable());
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
final int margin = Utils.dipToPixels(16);
toolbar.setTitleMargin(margin, 0, margin, 0);
TextView toolbarTextView = Utils.getChildView(toolbar,
true, TextView.class::isInstance);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(Utils.getAppForegroundColor());
toolbarTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
}
LicenseActivityHook.setToolbarLayoutParams(toolbar);
if (LicenseActivityHook.searchViewController != null
&& LicenseActivityHook.searchViewController.isSearchActive()) {
toolbar.post(() -> LicenseActivityHook.searchViewController.closeSearch());
}
rootView.addView(toolbar, 0);
return false;
}
);
}
}
}
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")

View File

@@ -0,0 +1,57 @@
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.SpoofVideoStreamsPatch;
@SuppressWarnings({"deprecation", "unused"})
public class SpoofAudioSelectorListPreference extends SortedListPreference {
private final boolean available;
{
if (SpoofVideoStreamsPatch.getLanguageOverride() != null) {
available = false;
super.setEnabled(false);
super.setSummary(str("revanced_spoof_video_streams_language_not_available"));
} else {
available = true;
}
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SpoofAudioSelectorListPreference(Context context) {
super(context);
}
@Override
public void setEnabled(boolean enabled) {
if (!available) {
return;
}
super.setEnabled(enabled);
}
@Override
public void setSummary(CharSequence summary) {
if (!available) {
return;
}
super.setSummary(summary);
}
}

View File

@@ -15,6 +15,7 @@ import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.spoof.ClientType; import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings({"deprecation", "unused"}) @SuppressWarnings({"deprecation", "unused"})
public class SpoofStreamingDataSideEffectsPreference extends Preference { public class SpoofStreamingDataSideEffectsPreference extends Preference {
@@ -69,7 +70,7 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
} }
private void updateUI() { private void updateUI() {
ClientType clientType = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get(); ClientType clientType = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
if (currentClientType == clientType) { if (currentClientType == clientType) {
return; return;
} }
@@ -78,21 +79,25 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
Logger.printDebug(() -> "Updating spoof stream side effects preference"); Logger.printDebug(() -> "Updating spoof stream side effects preference");
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get()); setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());
String key = "revanced_spoof_video_streams_about_" + setTitle(str("revanced_spoof_video_streams_about_title"));
(clientType == ClientType.IOS_UNPLUGGED
? "ios_tv"
: "android");
String title = str(key + "_title");
String summary = str(key + "_summary");
// Android VR supports AV1 but all other clients do not. String summary = str(clientType == ClientType.IPADOS
if (clientType != ClientType.ANDROID_VR_NO_AUTH) { ? "revanced_spoof_video_streams_about_ipados_summary"
// Same base side effects for Android VR, Android Studio, and visionOS.
: "revanced_spoof_video_streams_about_android_summary");
if (clientType == ClientType.IPADOS) {
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1"); summary += '\n' + str("revanced_spoof_video_streams_about_no_av1");
} else if (clientType == ClientType.VISIONOS) {
summary = str("revanced_spoof_video_streams_about_experimental")
+ '\n' + summary
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
+ '\n' + str("revanced_spoof_video_streams_about_kids_videos");
} else if (clientType == ClientType.ANDROID_CREATOR) {
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1")
+ '\n' + str("revanced_spoof_video_streams_about_kids_videos");
} }
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
setTitle(title);
setSummary(summary); setSummary(summary);
} }
} }

View File

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

View File

@@ -264,6 +264,14 @@ public final class app/revanced/patches/instagram/ads/HideAdsPatchKt {
public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/instagram/feed/LimitFeedToFollowedProfilesKt {
public static final fun getLimitFeedToFollowedProfiles ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt {
public static final fun getHideExportFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt { public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt {
public static final fun getHideNavigationButtonsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideNavigationButtonsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -272,6 +280,10 @@ public final class app/revanced/patches/instagram/hide/stories/HideStoriesKt {
public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/instagram/misc/extension/SharedExtensionPatchKt {
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt { public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -368,8 +380,9 @@ public final class app/revanced/patches/music/layout/premium/HideGetPremiumPatch
public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatchKt { public final class app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatchKt {
public static final fun getRemoveUpgradeButtonPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getHideUpgradeButton ()Lapp/revanced/patcher/patch/BytecodePatch;
public static final fun getRemoveUpgradeButton ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatchKt { public final class app/revanced/patches/music/misc/androidauto/BypassCertificateChecksPatchKt {
@@ -392,7 +405,21 @@ public final class app/revanced/patches/music/misc/gms/GmsCoreSupportPatchKt {
public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getGmsCoreSupportPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsKt { public final class app/revanced/patches/music/misc/settings/PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen {
public static final field INSTANCE Lapp/revanced/patches/music/misc/settings/PreferenceScreen;
public fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreenPreference;)V
public final fun getADS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
public final fun getGENERAL ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
public final fun getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
public final fun getPLAYER ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
}
public final class app/revanced/patches/music/misc/settings/SettingsPatchKt {
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
}
public final class app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatchKt {
public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSpoofVideoStreamsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -1648,7 +1675,6 @@ public final class app/revanced/patches/youtube/misc/settings/PreferenceScreen :
} }
public final class app/revanced/patches/youtube/misc/settings/SettingsPatchKt { public final class app/revanced/patches/youtube/misc/settings/SettingsPatchKt {
public static final fun addSettingPreference (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent; public static final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;
} }

View File

@@ -0,0 +1,20 @@
package app.revanced.patches.instagram.feed
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.BytecodePatchContext
internal val mainFeedRequestClassFingerprint = fingerprint {
strings("Request{mReason=", ", mInstanceNumber=")
}
context(BytecodePatchContext)
internal val initMainFeedRequestFingerprint get() = fingerprint {
custom { method, classDef ->
method.name == "<init>" &&
classDef == mainFeedRequestClassFingerprint.classDef
}
}
internal val mainFeedHeaderMapFinderFingerprint = fingerprint {
strings("pagination_source", "FEED_REQUEST_SENT")
}

View File

@@ -0,0 +1,63 @@
package app.revanced.patches.instagram.feed
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/instagram/feed/LimitFeedToFollowedProfiles;"
@Suppress("unused")
val limitFeedToFollowedProfiles = bytecodePatch(
name = "Limit feed to followed profiles",
description = "Filters the home feed to display only content from profiles you follow.",
) {
compatibleWith("com.instagram.android")
dependsOn(sharedExtensionPatch)
execute {
/**
* Since the header field is obfuscated and there is no easy way to identify it among all the class fields,
* an additional method is fingerprinted.
* This method uses the map, so we can get the field name of the map field using this.
*/
val mainFeedRequestHeaderFieldName: String
with(mainFeedHeaderMapFinderFingerprint.method) {
mainFeedRequestHeaderFieldName = indexOfFirstInstructionOrThrow {
getReference<FieldReference>().let { ref ->
ref?.type == "Ljava/util/Map;" &&
ref.definingClass == mainFeedRequestClassFingerprint.classDef.toString()
}
}.let { instructionIndex ->
getInstruction(instructionIndex).getReference<FieldReference>()!!.name
}
}
initMainFeedRequestFingerprint.method.apply {
// Finds the instruction where the map is being initialized in the constructor
val getHeaderIndex = indexOfFirstInstructionOrThrow {
getReference<FieldReference>().let {
it?.name == mainFeedRequestHeaderFieldName
}
}
val paramHeaderRegister = getInstruction<TwoRegisterInstruction>(getHeaderIndex).registerA
// Replace the `pagination_source` header value with `following` in the feed/timeline request.
addInstructions(
getHeaderIndex,
"""
invoke-static { v$paramHeaderRegister }, $EXTENSION_CLASS_DESCRIPTOR->setFollowingHeader(Ljava/util/Map;)Ljava/util/Map;
move-result-object v$paramHeaderRegister
"""
)
}
}
}

View File

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

View File

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

View File

@@ -23,7 +23,7 @@ internal val tabCreateButtonsLoopEndFingerprint = fingerprint {
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
// Injection Jump // Injection Jump
Opcode.ADD_INT_LIT8, //Increase Index Opcode.ADD_INT_LIT8, //Increase Index
Opcode.GOTO_16 // Jump to loopStart Opcode.GOTO // Jump to loopStart
// LoopEnd // LoopEnd
) )
} }

View File

@@ -15,7 +15,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
description = "Hides navigation bar buttons, such as the Reels and Create button.", description = "Hides navigation bar buttons, such as the Reels and Create button.",
use = false use = false
) { ) {
compatibleWith("com.instagram.android") compatibleWith("com.instagram.android"("397.1.0.52.81"))
val hideReels by booleanOption( val hideReels by booleanOption(
key = "hideReels", key = "hideReels",
@@ -49,7 +49,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
val freeRegister = findFreeRegister(insertIndex, loopIndexRegister) val freeRegister = findFreeRegister(insertIndex, loopIndexRegister)
val instruction = getInstruction(endIndex - 1) val instruction = getInstruction(endIndex - 1)
var instructions = buildString { val instructions = buildString {
if (hideCreate!!) { if (hideCreate!!) {
appendLine( appendLine(
""" """

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.instagram.misc.extension
import app.revanced.patches.instagram.misc.extension.hooks.applicationInitHook
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
val sharedExtensionPatch = sharedExtensionPatch(
"instagram",
applicationInitHook,
)

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.instagram.misc.extension.hooks
import app.revanced.patches.shared.misc.extension.extensionHook
internal val applicationInitHook = extensionHook {
custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/InstagramAppShell;")
}
}

View File

@@ -1,13 +1,27 @@
package app.revanced.patches.music.ad.video package app.revanced.patches.music.ad.video
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.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.settings.preference.SwitchPreference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideVideoAdsPatch;"
@Suppress("unused") @Suppress("unused")
val hideVideoAdsPatch = bytecodePatch( val hideVideoAdsPatch = bytecodePatch(
name = "Hide music video ads", name = "Hide music video ads",
description = "Hides ads that appear while listening to or streaming music videos, podcasts, or songs.", description = "Adds an option to hide ads that appear while listening to or streaming music videos, podcasts, or songs.",
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"
@@ -15,9 +29,21 @@ val hideVideoAdsPatch = bytecodePatch(
) )
execute { execute {
addResources("music", "ad.video.hideVideoAdsPatch")
PreferenceScreen.ADS.addPreferences(
SwitchPreference("revanced_music_hide_video_ads"),
)
navigate(showVideoAdsParentFingerprint.originalMethod) navigate(showVideoAdsParentFingerprint.originalMethod)
.to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1) .to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1)
.stop() .stop()
.addInstruction(0, "const/4 p1, 0x0") .addInstructions(
0,
"""
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->showVideoAds(Z)Z
move-result p1
"""
)
} }
} }

View File

@@ -1,6 +1,8 @@
package app.revanced.patches.music.audio.exclusiveaudio package app.revanced.patches.music.audio.exclusiveaudio
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
@Suppress("unused") @Suppress("unused")
@@ -8,6 +10,11 @@ val enableExclusiveAudioPlaybackPatch = bytecodePatch(
name = "Enable exclusive audio playback", name = "Enable exclusive audio playback",
description = "Enables the option to play audio without video.", description = "Enables the option to play audio without video.",
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"

View File

@@ -4,13 +4,27 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.all.misc.resources.addResources
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.settings.preference.SwitchPreference
import app.revanced.util.findFreeRegister
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/PermanentRepeatPatch;"
@Suppress("unused") @Suppress("unused")
val permanentRepeatPatch = bytecodePatch( val permanentRepeatPatch = bytecodePatch(
name = "Permanent repeat", name = "Permanent repeat",
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.", description = "Adds an option to always repeat even if the playlist ends or another track is played."
use = false,
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"
@@ -18,13 +32,27 @@ val permanentRepeatPatch = bytecodePatch(
) )
execute { execute {
addResources("music", "interaction.permanentrepeat.permanentRepeatPatch")
PreferenceScreen.PLAYER.addPreferences(
SwitchPreference("revanced_music_play_permanent_repeat"),
)
val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex
val repeatIndex = startIndex + 1 val repeatIndex = startIndex + 1
repeatTrackFingerprint.method.apply { repeatTrackFingerprint.method.apply {
// Start index is at a branch, but the same
// register is clobbered in both branch paths.
val freeRegister = findFreeRegister(startIndex + 1)
addInstructionsWithLabels( addInstructionsWithLabels(
startIndex, startIndex,
"goto :repeat", """
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->permanentRepeat()Z
move-result v$freeRegister
if-nez v$freeRegister, :repeat
""",
ExternalLabel("repeat", instructions[repeatIndex]), ExternalLabel("repeat", instructions[repeatIndex]),
) )
} }

View File

@@ -1,17 +1,32 @@
package app.revanced.patches.music.layout.compactheader package app.revanced.patches.music.layout.compactheader
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.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.settings.preference.SwitchPreference
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.findFreeRegister import app.revanced.util.findFreeRegister
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
@Suppress("unused") @Suppress("unused")
val hideCategoryBar = bytecodePatch( val hideCategoryBar = bytecodePatch(
name = "Hide category bar", name = "Hide category bar",
description = "Hides the category bar at the top of the homepage.", description = "Adds an option to hide the category bar at the top of the homepage."
use = false,
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"
@@ -19,16 +34,27 @@ val hideCategoryBar = bytecodePatch(
) )
execute { execute {
addResources("music", "layout.compactheader.hideCategoryBar")
PreferenceScreen.GENERAL.addPreferences(
SwitchPreference("revanced_music_hide_category_bar"),
)
constructCategoryBarFingerprint.method.apply { constructCategoryBarFingerprint.method.apply {
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
val freeRegister = findFreeRegister(insertIndex, register) val freeRegister = findFreeRegister(insertIndex, register)
addInstructions( addInstructionsWithLabels(
insertIndex, insertIndex,
""" """
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar()Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
const/16 v$freeRegister, 0x8 const/16 v$freeRegister, 0x8
invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V
:show
nop
""" """
) )
} }

View File

@@ -1,16 +1,31 @@
package app.revanced.patches.music.layout.premium package app.revanced.patches.music.layout.premium
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.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.settings.preference.SwitchPreference
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideGetPremiumPatch;"
@Suppress("unused")
val hideGetPremiumPatch = bytecodePatch( val hideGetPremiumPatch = bytecodePatch(
name = "Hide 'Get Music Premium' label", name = "Hide 'Get Music Premium'",
description = "Hides the \"Get Music Premium\" label from the account menu and settings.", description = "Adds an option to hide the \"Get Music Premium\" label in the settings and account menu.",
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"
@@ -18,6 +33,12 @@ val hideGetPremiumPatch = bytecodePatch(
) )
execute { execute {
addResources("music", "layout.premium.hideGetPremiumPatch")
PreferenceScreen.ADS.addPreferences(
SwitchPreference("revanced_music_hide_get_premium_label"),
)
hideGetPremiumFingerprint.method.apply { hideGetPremiumFingerprint.method.apply {
val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex
@@ -37,12 +58,17 @@ val hideGetPremiumPatch = bytecodePatch(
) )
} }
membershipSettingsFingerprint.method.addInstructions( membershipSettingsFingerprint.method.addInstructionsWithLabels(
0, 0,
""" """
const/4 v0, 0x0 invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideGetPremiumLabel()Z
return-object v0 move-result v0
""", if-eqz v0, :show
const/4 v0, 0x0
return-object v0
:show
nop
"""
) )
} }
} }

View File

@@ -7,17 +7,31 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.extensions.newLabel import app.revanced.patcher.extensions.newLabel
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.toInstructions import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.all.misc.resources.addResources
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.settings.preference.SwitchPreference
import app.revanced.util.getReference import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;"
@Suppress("unused") @Suppress("unused")
val removeUpgradeButtonPatch = bytecodePatch( val hideUpgradeButton = bytecodePatch(
name = "Remove upgrade button", name = "Hide upgrade button",
description = "Removes the upgrade tab from the pivot bar.", description = "Hides the upgrade tab from the pivot bar.",
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"
@@ -25,6 +39,15 @@ val removeUpgradeButtonPatch = bytecodePatch(
) )
execute { execute {
addResources("music", "layout.upgradebutton.hideUpgradeButtonPatch")
// TODO: Add an extension patch to allow this to be enabled/disabled in app.
if (false) {
PreferenceScreen.ADS.addPreferences(
SwitchPreference("revanced_music_hide_upgrade_button")
)
}
pivotBarConstructorFingerprint.method.apply { pivotBarConstructorFingerprint.method.apply {
val pivotBarElementFieldReference = val pivotBarElementFieldReference =
getInstruction(pivotBarConstructorFingerprint.patternMatch!!.endIndex - 1) getInstruction(pivotBarConstructorFingerprint.patternMatch!!.endIndex - 1)
@@ -77,3 +100,9 @@ val removeUpgradeButtonPatch = bytecodePatch(
} }
} }
} }
@Deprecated("Patch was renamed", ReplaceWith("hideUpgradeButton"))
@Suppress("unused")
val removeUpgradeButton = bytecodePatch{
dependsOn(hideUpgradeButton)
}

View File

@@ -1,6 +1,8 @@
package app.revanced.patches.music.misc.androidauto package app.revanced.patches.music.misc.androidauto
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
@Suppress("unused") @Suppress("unused")
@@ -8,6 +10,11 @@ val bypassCertificateChecksPatch = bytecodePatch(
name = "Bypass certificate checks", name = "Bypass certificate checks",
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.", description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"

View File

@@ -1,13 +1,20 @@
package app.revanced.patches.music.misc.backgroundplayback package app.revanced.patches.music.misc.backgroundplayback
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.util.returnEarly
val backgroundPlaybackPatch = bytecodePatch( val backgroundPlaybackPatch = bytecodePatch(
name = "Remove background playback restrictions", name = "Remove background playback restrictions",
description = "Removes restrictions on background playback, including playing kids videos in the background.", description = "Removes restrictions on background playback, including playing kids videos in the background.",
) { ) {
dependsOn(
sharedExtensionPatch,
settingsPatch
)
compatibleWith( compatibleWith(
"com.google.android.apps.youtube.music"( "com.google.android.apps.youtube.music"(
"7.29.52" "7.29.52"
@@ -20,12 +27,6 @@ val backgroundPlaybackPatch = bytecodePatch(
"return-void", "return-void",
) )
backgroundPlaybackDisableFingerprint.method.addInstructions( backgroundPlaybackDisableFingerprint.method.returnEarly(true)
0,
"""
const/4 v0, 0x1
return v0
""",
)
} }
} }

View File

@@ -1,12 +1,17 @@
package app.revanced.patches.music.misc.gms package app.revanced.patches.music.misc.gms
import app.revanced.patcher.patch.Option import app.revanced.patcher.patch.Option
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.shared.castContextFetchFingerprint import app.revanced.patches.shared.castContextFetchFingerprint
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.primeMethodFingerprint import app.revanced.patches.shared.primeMethodFingerprint
@Suppress("unused") @Suppress("unused")
@@ -33,4 +38,23 @@ private fun gmsCoreSupportResourcePatch(
toPackageName = REVANCED_MUSIC_PACKAGE_NAME, toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption, gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
spoofedPackageSignature = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875", spoofedPackageSignature = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875",
) executeBlock = {
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
PreferenceScreen.MISC.addPreferences(
IntentPreference(
"microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms"
}
)
)
}
) {
dependsOn(
addResourcesPatch,
settingsPatch
)
}

View File

@@ -0,0 +1,11 @@
package app.revanced.patches.music.misc.settings
import app.revanced.patcher.fingerprint
internal val googleApiActivityFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
classDef.endsWith("GoogleApiActivity;") && method.name == "onCreate"
}
}

View File

@@ -0,0 +1,176 @@
package app.revanced.patches.music.misc.settings
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.*
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.misc.settings.settingsPatch
import app.revanced.util.*
import com.android.tools.smali.dexlib2.util.MethodUtil
private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
private const val GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/settings/GoogleApiActivityHook;"
private val preferences = mutableSetOf<BasePreference>()
private val settingsResourcePatch = resourcePatch {
dependsOn(
resourceMappingPatch,
settingsPatch(
IntentPreference(
titleKey = "revanced_settings_title",
summaryKey = null,
intent = newIntent("revanced_settings_intent"),
) to "settings_headers",
preferences
)
)
execute {
// TODO: Remove this when search will be abstract.
copyResources(
"settings",
ResourceGroup(
"layout",
"revanced_music_settings_with_toolbar.xml"
)
)
val targetResource = "values/styles.xml"
inputStreamFromBundledResource(
"settings/music",
targetResource,
)!!.let { inputStream ->
"resources".copyXmlNode(
document(inputStream),
document("res/$targetResource"),
).close()
}
// Remove horizontal divider from the settings Preferences.
val styleFile = get("res/values/styles.xml")
styleFile.writeText(
styleFile.readText()
.replace(
"allowDividerAbove\">true",
"allowDividerAbove\">false"
).replace(
"allowDividerBelow\">true",
"allowDividerBelow\">false"
)
)
}
}
val settingsPatch = bytecodePatch(
description = "Adds settings for ReVanced to YouTube Music.",
) {
dependsOn(
sharedExtensionPatch,
settingsResourcePatch,
addResourcesPatch,
)
execute {
addResources("music", "misc.settings.settingsPatch")
addResources("shared", "misc.debugging.enableDebuggingPatch")
// Should make a separate debugging patch, but for now include it with all installations.
PreferenceScreen.MISC.addPreferences(
PreferenceScreenPreference(
key = "revanced_debug_screen",
sorting = Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_debug"),
NonInteractivePreference(
"revanced_debug_export_logs_to_clipboard",
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
selectable = true
),
NonInteractivePreference(
"revanced_debug_logs_clear_buffer",
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
selectable = true
)
)
)
)
// Add an "About" preference to the top.
preferences += NonInteractivePreference(
key = "revanced_settings_music_screen_0_about",
summaryKey = null,
tag = "app.revanced.extension.shared.settings.preference.ReVancedAboutPreference",
selectable = true,
)
// Modify GoogleApiActivity and remove all existing layout code.
// Must modify an existing activity and cannot add a new activity to the manifest,
// as that fails for root installations.
googleApiActivityFingerprint.method.addInstructions(
1,
"""
invoke-static { }, $GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/music/settings/GoogleApiActivityHook;
move-result-object v0
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
return-void
"""
)
// Remove other methods as they will break as the onCreate method is modified above.
googleApiActivityFingerprint.classDef.apply {
methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
}
}
finalize {
PreferenceScreen.close()
}
}
/**
* Creates an intent to open ReVanced settings.
*/
fun newIntent(settingsName: String) = IntentPreference.Intent(
data = settingsName,
targetClass = "com.google.android.gms.common.api.GoogleApiActivity"
) {
// The package name change has to be reflected in the intent.
setOrGetFallbackPackageName("com.google.android.apps.youtube.music")
}
object PreferenceScreen : BasePreferenceScreen() {
val ADS = Screen(
"revanced_settings_music_screen_1_ads",
summaryKey = null
)
val GENERAL = Screen(
"revanced_settings_music_screen_2_general",
summaryKey = null
)
val PLAYER = Screen(
"revanced_settings_music_screen_3_player",
summaryKey = null
)
val MISC = Screen(
"revanced_settings_music_screen_4_misc",
summaryKey = null
)
override fun commit(screen: PreferenceScreenPreference) {
preferences += screen
}
}

View File

@@ -1,23 +0,0 @@
package app.revanced.patches.music.misc.spoof
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
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
import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
block = {
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
)
)
dependsOn(sharedExtensionPatch, versionCheckPatch, userAgentClientSpoofPatch)
},
fixMediaFetchHotConfigChanges = { true },
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater }
)

View File

@@ -0,0 +1,59 @@
package app.revanced.patches.music.misc.spoof
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
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_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
import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
fixMediaFetchHotConfigChanges = { true },
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
block = {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
versionCheckPatch,
userAgentClientSpoofPatch
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
)
)
},
executeBlock = {
addResources("music", "misc.fix.playback.spoofVideoStreamsPatch")
PreferenceScreen.MISC.addPreferences(
PreferenceScreenPreference(
key = "revanced_spoof_video_streams_screen",
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_spoof_video_streams"),
ListPreference("revanced_spoof_video_streams_client_type"),
)
)
)
musicActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
)
}
)

View File

@@ -150,7 +150,6 @@ internal val nerdsStatsVideoFormatBuilderFingerprint = fingerprint {
} }
internal val patchIncludedExtensionMethodFingerprint = fingerprint { internal val patchIncludedExtensionMethodFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Z") returns("Z")
parameters() parameters()
custom { method, classDef -> custom { method, classDef ->

View File

@@ -9,8 +9,8 @@ import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.util.findFreeRegister import app.revanced.util.findFreeRegister
import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference import app.revanced.util.getReference
@@ -46,6 +46,8 @@ fun spoofVideoStreamsPatch(
dependsOn(addResourcesPatch) dependsOn(addResourcesPatch)
execute { execute {
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
// region Enable extension helper method used by other patches // region Enable extension helper method used by other patches
patchIncludedExtensionMethodFingerprint.method.returnEarly(true) patchIncludedExtensionMethodFingerprint.method.returnEarly(true)

View File

@@ -187,11 +187,16 @@ val customThemePatch = resourcePatch(
} }
// Login screen gradient. // Login screen gradient.
document("res/drawable/start_screen_gradient.xml").use { document -> try {
val gradientNode = document.getElementsByTagName("gradient").item(0) as Element document("res/drawable/start_screen_gradient.xml").use { document ->
val gradientNode = document.getElementsByTagName("gradient").item(0) as Element
gradientNode.setAttribute("android:startColor", "@color/gray_7") gradientNode.setAttribute("android:startColor", "@color/gray_7")
gradientNode.setAttribute("android:endColor", "@color/gray_7") gradientNode.setAttribute("android:endColor", "@color/gray_7")
}
} catch (_: Exception) {
// Fails for 9.0.66+
// printWarn("Failed to locate start_screen_gradient.xml, skipping modification.")
} }
} }
} }

View File

@@ -12,9 +12,9 @@ import app.revanced.util.returnEarly
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/fix/SpoofClientPatch;" internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/spotify/misc/fix/SpoofClientPatch;"
@Deprecated("Patch no longer functions")
@Suppress("unused") @Suppress("unused")
val spoofClientPatch = bytecodePatch( val spoofClientPatch = bytecodePatch(
name = "Spoof client",
description = "Spoofs the client to fix various functions of the app.", description = "Spoofs the client to fix various functions of the app.",
) { ) {
val requestListenerPort by intOption( val requestListenerPort by intOption(

View File

@@ -2,12 +2,6 @@ package app.revanced.patches.viber.ads
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
internal val adsFreeFingerprint = fingerprint { internal val findAdStringFingerprint = fingerprint {
returns("I") strings("viber_plus_debug_ads_free_flag")
parameters()
custom { method, classDef ->
classDef.type.contains("com/viber/voip/feature/viberplus") &&
classDef.superclass?.contains("com/viber/voip/core/feature") == true && // Must extend com.viber.voip.core.feature.?
classDef.methods.count() == 1
}
} }

View File

@@ -1,17 +1,41 @@
package app.revanced.patches.viber.ads package app.revanced.patches.viber.ads
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.returnEarly import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
@Suppress("unused") @Suppress("unused")
val hideAdsPatch = bytecodePatch( val hideAdsPatch = bytecodePatch(
name = "Hide Ads", name = "Hide Ads",
description = "Hides ad banners between chats.", description = "Hides ad banners between chats.",
) { ) {
compatibleWith("com.viber.voip") compatibleWith("com.viber.voip"("25.9.2.0", "26.1.2.0"))
execute { execute {
// Return 1 (true) indicating ads should be disabled. val method = findAdStringFingerprint.method
adsFreeFingerprint.method.returnEarly(1)
// Find the ads free string index
val stringIndex = findAdStringFingerprint.stringMatches!!.first().index
// Search backwards from the string to find the `new-instance` (TypeReference) instruction
val typeRefIndex = method.indexOfFirstInstructionReversedOrThrow(stringIndex) { this.opcode == Opcode.NEW_INSTANCE }
// Get the class name from the TypeReference
val targetClass = method.getInstruction<ReferenceInstruction>(typeRefIndex).reference as TypeReference
// Patch the ads-free method to always return true
fingerprint {
returns("I")
parameters()
custom { method, classDef ->
classDef == targetClass
}
}.method.returnEarly(1)
} }
} }

View File

@@ -89,7 +89,7 @@ val downloadsPatch = bytecodePatch(
// Main activity is used to launch downloader intent. // Main activity is used to launch downloader intent.
mainActivityOnCreateFingerprint.method.addInstruction( mainActivityOnCreateFingerprint.method.addInstruction(
1, 0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V" "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V"
) )

View File

@@ -49,6 +49,7 @@ val hideButtonsPatch = resourcePatch(
SwitchPreference("revanced_hide_report_button"), SwitchPreference("revanced_hide_report_button"),
SwitchPreference("revanced_hide_save_button"), SwitchPreference("revanced_hide_save_button"),
SwitchPreference("revanced_hide_share_button"), SwitchPreference("revanced_hide_share_button"),
SwitchPreference("revanced_hide_shop_button"),
SwitchPreference("revanced_hide_stop_ads_button"), SwitchPreference("revanced_hide_stop_ads_button"),
SwitchPreference("revanced_hide_thanks_button"), SwitchPreference("revanced_hide_thanks_button"),
) )

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.seekbar package app.revanced.patches.youtube.layout.seekbar
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
import app.revanced.util.containsLiteralInstruction import app.revanced.util.containsLiteralInstruction
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
@@ -103,7 +104,7 @@ internal val launchScreenLayoutTypeFingerprint = fingerprint {
custom { method, _ -> custom { method, _ ->
val firstParameter = method.parameterTypes.firstOrNull() val firstParameter = method.parameterTypes.firstOrNull()
// 19.25 - 19.45 // 19.25 - 19.45
(firstParameter == "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;" (firstParameter == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
|| firstParameter == "Landroid/app/Activity;") // 19.46+ || firstParameter == "Landroid/app/Activity;") // 19.46+
&& method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag) && method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag)
} }

View File

@@ -68,7 +68,7 @@ val shortsAutoplayPatch = bytecodePatch(
// Main activity is used to check if app is in pip mode. // Main activity is used to check if app is in pip mode.
mainActivityOnCreateFingerprint.method.addInstruction( mainActivityOnCreateFingerprint.method.addInstruction(
1, 0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->setMainActivity(Landroid/app/Activity;)V", "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->setMainActivity(Landroid/app/Activity;)V",
) )

View File

@@ -90,8 +90,8 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
// Activity is used as the context to launch an Intent. // Activity is used as the context to launch an Intent.
mainActivityOnCreateFingerprint.method.addInstruction( mainActivityOnCreateFingerprint.method.addInstruction(
1, 0,
"invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->" + "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setMainActivity(Landroid/app/Activity;)V", "setMainActivity(Landroid/app/Activity;)V",
) )

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.theme package app.revanced.patches.youtube.layout.theme
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
import app.revanced.util.literal import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@@ -37,6 +38,6 @@ internal val splashScreenStyleFingerprint = fingerprint {
parameters("Landroid/os/Bundle;") parameters("Landroid/os/Bundle;")
literal { SPLASH_SCREEN_STYLE_FEATURE_FLAG } literal { SPLASH_SCREEN_STYLE_FEATURE_FLAG }
custom { method, classDef -> custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/MainActivity;") method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
} }
} }

View File

@@ -40,9 +40,7 @@ val announcementsPatch = bytecodePatch(
) )
mainActivityOnCreateFingerprint.method.addInstruction( mainActivityOnCreateFingerprint.method.addInstruction(
// Insert index must be greater than the insert index used by GmsCoreSupport, 0,
// as both patch the same method and GmsCore check should be first.
1,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->showAnnouncement(Landroid/app/Activity;)V", "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->showAnnouncement(Landroid/app/Activity;)V",
) )
} }

View File

@@ -22,6 +22,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/EnableDebuggingPatch;" "Lapp/revanced/extension/youtube/patches/EnableDebuggingPatch;"
// TODO: Refactor this into a shared patch that can be used by both YT and YT Music.
// Almost all of the feature flag hooks are the same between both apps.
val enableDebuggingPatch = bytecodePatch( val enableDebuggingPatch = bytecodePatch(
name = "Enable debugging", name = "Enable debugging",
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.", description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
@@ -45,6 +47,7 @@ val enableDebuggingPatch = bytecodePatch(
) )
execute { execute {
addResources("shared", "misc.debugging.enableDebuggingPatch")
addResources("youtube", "misc.debugging.enableDebuggingPatch") addResources("youtube", "misc.debugging.enableDebuggingPatch")
PreferenceScreen.MISC.addPreferences( PreferenceScreen.MISC.addPreferences(
@@ -58,13 +61,13 @@ val enableDebuggingPatch = bytecodePatch(
SwitchPreference("revanced_debug_toast_on_error"), SwitchPreference("revanced_debug_toast_on_error"),
NonInteractivePreference( NonInteractivePreference(
"revanced_debug_export_logs_to_clipboard", "revanced_debug_export_logs_to_clipboard",
tag = "app.revanced.extension.youtube.settings.preference.ExportLogToClipboardPreference", tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
selectable = true, selectable = true
), ),
NonInteractivePreference( NonInteractivePreference(
"revanced_debug_logs_clear_buffer", "revanced_debug_logs_clear_buffer",
tag = "app.revanced.extension.youtube.settings.preference.ClearLogBufferPreference", tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
selectable = true, selectable = true
), ),
), ),
), ),

View File

@@ -34,12 +34,7 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
addResources("youtube", "misc.dns.checkWatchHistoryDomainNameResolutionPatch") addResources("youtube", "misc.dns.checkWatchHistoryDomainNameResolutionPatch")
mainActivityOnCreateFingerprint.method.addInstruction( mainActivityOnCreateFingerprint.method.addInstruction(
// FIXME: Insert index must be greater than the insert index used by GmsCoreSupport, 0,
// as both patch the same method and GmsCoreSupport check should be first,
// but the patch does not depend on GmsCoreSupport, so it should not be possible to enforce this
// unless a third patch is added that this patch and GmsCoreSupport depend on to manage
// the order of the patches.
1,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V", "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V",
) )
} }

View File

@@ -3,4 +3,5 @@ package app.revanced.patches.youtube.misc.extension
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.extension.hooks.* import app.revanced.patches.youtube.misc.extension.hooks.*
val sharedExtensionPatch = sharedExtensionPatch("youtube", applicationInitHook) val sharedExtensionPatch = sharedExtensionPatch("youtube",
applicationInitHook, applicationInitOnCrateHook)

View File

@@ -1,11 +1,23 @@
package app.revanced.patches.youtube.misc.extension.hooks package app.revanced.patches.youtube.misc.extension.hooks
import app.revanced.patches.shared.misc.extension.extensionHook import app.revanced.patches.shared.misc.extension.extensionHook
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
/** /**
* Hooks the context when the app is launched as a regular application (and is not an embedded video playback). * Hooks the context when the app is launched as a regular application (and is not an embedded video playback).
*/ */
// Extension context is the Activity itself. // Extension context is the Activity itself.
internal val applicationInitHook = extensionHook { internal val applicationInitHook = extensionHook {
// Does _not_ resolve to the YouTube main activity.
// Required as some hooked code runs before the main activity is launched.
strings("Application creation", "Application.onCreate") strings("Application creation", "Application.onCreate")
} }
internal val applicationInitOnCrateHook = extensionHook {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
}
}

View File

@@ -53,7 +53,7 @@ private fun gmsCoreSupportResourcePatch(
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption, gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600", spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
executeBlock = { executeBlock = {
addResources("youtube", "misc.gms.gmsCoreSupportResourcePatch") addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
@@ -62,10 +62,14 @@ private fun gmsCoreSupportResourcePatch(
"microg_settings", "microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") { intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$gmsCoreVendorGroupId.android.gms" "$gmsCoreVendorGroupId.android.gms"
}, }
), )
) )
}, }
) { ) {
dependsOn(settingsPatch, addResourcesPatch, accountCredentialsInvalidTextPatch) dependsOn(
addResourcesPatch,
settingsPatch,
accountCredentialsInvalidTextPatch
)
} }

View File

@@ -127,8 +127,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
// Litho filtering based on navigation tab before the tab is updated. // Litho filtering based on navigation tab before the tab is updated.
mainActivityOnBackPressedFingerprint.method.addInstruction( mainActivityOnBackPressedFingerprint.method.addInstruction(
0, 0,
"invoke-static { p0 }, " + "invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V",
"$EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V",
) )
// Hook the search bar. // Hook the search bar.

View File

@@ -29,7 +29,9 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.util.MethodUtil import com.android.tools.smali.dexlib2.util.MethodUtil
private const val EXTENSION_CLASS_DESCRIPTOR = private const val BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/settings/BaseActivityHook;"
private const val LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/settings/LicenseActivityHook;" "Lapp/revanced/extension/youtube/settings/LicenseActivityHook;"
internal var appearanceStringId = -1L internal var appearanceStringId = -1L
@@ -37,10 +39,6 @@ internal var appearanceStringId = -1L
private val preferences = mutableSetOf<BasePreference>() private val preferences = mutableSetOf<BasePreference>()
fun addSettingPreference(screen: BasePreference) {
preferences += screen
}
private val settingsResourcePatch = resourcePatch { private val settingsResourcePatch = resourcePatch {
dependsOn( dependsOn(
resourceMappingPatch, resourceMappingPatch,
@@ -225,7 +223,9 @@ val settingsPatch = bytecodePatch(
licenseActivityOnCreateFingerprint.method.addInstructions( licenseActivityOnCreateFingerprint.method.addInstructions(
1, 1,
""" """
invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V invoke-static {}, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->createInstance()Lapp/revanced/extension/youtube/settings/LicenseActivityHook;
move-result-object v0
invoke-static { v0, p0 }, $BASE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Lapp/revanced/extension/shared/settings/BaseActivityHook;Landroid/app/Activity;)V
return-void return-void
""" """
) )
@@ -249,7 +249,7 @@ val settingsPatch = bytecodePatch(
).toMutable().apply { ).toMutable().apply {
addInstructions( addInstructions(
""" """
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context; invoke-static { p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->getAttachBaseContext(Landroid/content/Context;)Landroid/content/Context;
move-result-object p1 move-result-object p1
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
return-void return-void
@@ -294,7 +294,7 @@ val settingsPatch = bytecodePatch(
addInstructions( addInstructions(
""" """
invoke-super { p0, p1 }, Landroid/app/Activity;->onConfigurationChanged(Landroid/content/res/Configuration;)V invoke-super { p0, p1 }, Landroid/app/Activity;->onConfigurationChanged(Landroid/content/res/Configuration;)V
invoke-static { p0, p1 }, $EXTENSION_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V invoke-static { p0, p1 }, $LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->handleConfigurationChanged(Landroid/app/Activity;Landroid/content/res/Configuration;)V
return-void return-void
""" """
) )
@@ -309,15 +309,15 @@ val settingsPatch = bytecodePatch(
val register = getInstruction<OneRegisterInstruction>(index).registerA val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructionsAtControlFlowLabel( addInstructionsAtControlFlowLabel(
index, index,
"invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V", "invoke-static { v$register }, ${LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR}->updateLightDarkModeStatus(Ljava/lang/Enum;)V",
) )
} }
} }
// Add setting to force cairo settings fragment on/off. // Add setting to force Cairo settings fragment on/off.
cairoFragmentConfigFingerprint.method.insertLiteralOverride( cairoFragmentConfigFingerprint.method.insertLiteralOverride(
CAIRO_CONFIG_LITERAL_VALUE, CAIRO_CONFIG_LITERAL_VALUE,
"$EXTENSION_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z" "$LICENSE_ACTIVITY_HOOK_CLASS_DESCRIPTOR->useCairoSettingsFragment(Z)Z"
) )
} }

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.misc.spoof package app.revanced.patches.youtube.misc.spoof
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patches.all.misc.resources.addResources import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
@@ -13,56 +14,69 @@ import app.revanced.patches.youtube.misc.playservice.is_20_14_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
val spoofVideoStreamsPatch = spoofVideoStreamsPatch({ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;"
compatibleWith(
"com.google.android.youtube"( val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
"19.34.42", block = {
"19.43.41", compatibleWith(
"19.47.53", "com.google.android.youtube"(
"20.07.39", "19.34.42",
"20.12.46", "19.43.41",
"20.13.41", "19.47.53",
"20.07.39",
"20.12.46",
"20.13.41",
)
) )
)
dependsOn( dependsOn(
userAgentClientSpoofPatch, userAgentClientSpoofPatch,
settingsPatch, settingsPatch,
versionCheckPatch versionCheckPatch
) )
}, { },
is_19_34_or_greater fixMediaFetchHotConfigChanges = {
}, { is_19_34_or_greater
// In 20.14 the flag was merged with 20.03 start playback flag. },
is_20_10_or_greater && !is_20_14_or_greater fixMediaFetchHotConfigAlternativeChanges = {
}, { // In 20.14 the flag was merged with 20.03 start playback flag.
is_20_03_or_greater is_20_10_or_greater && !is_20_14_or_greater
}, { },
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch") fixParsePlaybackResponseFeatureFlag = {
is_20_03_or_greater
},
executeBlock = {
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
PreferenceScreen.MISC.addPreferences( PreferenceScreen.MISC.addPreferences(
PreferenceScreenPreference( PreferenceScreenPreference(
key = "revanced_spoof_video_streams_screen", key = "revanced_spoof_video_streams_screen",
sorting = PreferenceScreenPreference.Sorting.UNSORTED, sorting = PreferenceScreenPreference.Sorting.UNSORTED,
preferences = setOf( preferences = setOf(
SwitchPreference("revanced_spoof_video_streams"), SwitchPreference("revanced_spoof_video_streams"),
ListPreference("revanced_spoof_video_streams_client_type"), ListPreference("revanced_spoof_video_streams_client_type"),
NonInteractivePreference( NonInteractivePreference(
// Requires a key and title but the actual text is chosen at runtime. // Requires a key and title but the actual text is chosen at runtime.
key = "revanced_spoof_video_streams_about_android", key = "revanced_spoof_video_streams_about_android",
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference" tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
), ),
ListPreference( ListPreference(
key = "revanced_spoof_video_streams_language", key = "revanced_spoof_video_streams_language",
// Language strings are declared in Setting patch. // Language strings are declared in Setting patch.
entriesKey = "revanced_language_entries", entriesKey = "revanced_language_entries",
entryValuesKey = "revanced_language_entry_values", entryValuesKey = "revanced_language_entry_values",
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference" tag = "app.revanced.extension.youtube.settings.preference.SpoofAudioSelectorListPreference"
), ),
SwitchPreference("revanced_spoof_video_streams_ios_force_avc"), SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"),
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"), )
), )
), )
)
}) mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
)
}
)

View File

@@ -4,6 +4,8 @@ import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal const val YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE = "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;"
internal val conversionContextFingerprintToString = fingerprint { internal val conversionContextFingerprintToString = fingerprint {
parameters() parameters()
strings( strings(
@@ -48,7 +50,7 @@ internal val mainActivityConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters() parameters()
custom { _, classDef -> custom { _, classDef ->
classDef.endsWith("/MainActivity;") classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
} }
} }
@@ -57,7 +59,7 @@ internal val mainActivityOnBackPressedFingerprint = fingerprint {
returns("V") returns("V")
parameters() parameters()
custom { method, classDef -> custom { method, classDef ->
method.name == "onBackPressed" && classDef.endsWith("/MainActivity;") method.name == "onBackPressed" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
} }
} }
@@ -65,7 +67,7 @@ internal val mainActivityOnCreateFingerprint = fingerprint {
returns("V") returns("V")
parameters("Landroid/os/Bundle;") parameters("Landroid/os/Bundle;")
custom { method, classDef -> custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/MainActivity;") method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
} }
} }

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.video.audio package app.revanced.patches.youtube.video.audio
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
@@ -14,6 +15,7 @@ import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.findMethodFromToString import app.revanced.util.findMethodFromToString
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.insertLiteralOverride import app.revanced.util.insertLiteralOverride
@@ -61,6 +63,11 @@ val forceOriginalAudioPatch = bytecodePatch(
) )
) )
mainActivityOnCreateFingerprint.method.addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setPreferredLanguage()V"
)
// Disable feature flag that ignores the default track flag // Disable feature flag that ignores the default track flag
// and instead overrides to the user region language. // and instead overrides to the user region language.
if (is_20_07_or_greater) { if (is_20_07_or_greater) {

View File

@@ -30,6 +30,10 @@ Second \"item\" text"</string>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -96,6 +100,7 @@ Second \"item\" text"</string>
<!-- 'Ask' should be translated with the same localized wording that YouTube displays. <!-- 'Ask' should be translated with the same localized wording that YouTube displays.
This button only shows if the user ip is from specific region such as the USA or EU. --> This button only shows if the user ip is from specific region such as the USA or EU. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. --> <!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch> </patch>
<patch id="layout.buttons.navigation.navigationButtonsPatch"> <patch id="layout.buttons.navigation.navigationButtonsPatch">
@@ -207,8 +212,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
</patch> </patch>
<patch id="misc.gms.accountCredentialsInvalidTextPatch"> <patch id="misc.gms.accountCredentialsInvalidTextPatch">
@@ -240,6 +243,21 @@ Second \"item\" text"</string>
<patch id="interaction.seekbar.enableSlideToSeekPatch"> <patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
</patch>
<patch id="ad.video.hideVideoAdsPatch">
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
</patch>
<patch id="layout.compactheader.hideCategoryBar">
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -30,6 +30,10 @@ Second \"item\" text"</string>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -96,6 +100,7 @@ Second \"item\" text"</string>
<!-- 'Ask' should be translated with the same localized wording that YouTube displays. <!-- 'Ask' should be translated with the same localized wording that YouTube displays.
This button only shows if the user ip is from specific region such as the USA or EU. --> This button only shows if the user ip is from specific region such as the USA or EU. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. --> <!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch> </patch>
<patch id="layout.buttons.navigation.navigationButtonsPatch"> <patch id="layout.buttons.navigation.navigationButtonsPatch">
@@ -207,8 +212,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
</patch> </patch>
<patch id="misc.gms.accountCredentialsInvalidTextPatch"> <patch id="misc.gms.accountCredentialsInvalidTextPatch">
@@ -240,6 +243,21 @@ Second \"item\" text"</string>
<patch id="interaction.seekbar.enableSlideToSeekPatch"> <patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
</patch>
<patch id="ad.video.hideVideoAdsPatch">
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
</patch>
<patch id="layout.compactheader.hideCategoryBar">
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. --> and changes made here must also be made there. -->
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">ØĨؚداداØĒ GmsCore</string>
<string name="microg_settings_summary">ØĨؚداداØĒ Ų„Ų€ GmsCore</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="gms_core_toast_not_installed_message">Ų„Ų… ؊ØĒŲ… ØĒØĢØ¨ŲŠØĒ MicroG GmsCore. Ų‚Ų… بØĒØĢØ¨ŲŠØĒŲ‡.</string> <string name="gms_core_toast_not_installed_message">Ų„Ų… ؊ØĒŲ… ØĒØĢØ¨ŲŠØĒ MicroG GmsCore. Ų‚Ų… بØĒØĢØ¨ŲŠØĒŲ‡.</string>
<string name="gms_core_dialog_title">Ø§Ų„ØĨØŦØąØ§ØĄ Ų…ØˇŲ„ŲˆØ¨</string> <string name="gms_core_dialog_title">Ø§Ų„ØĨØŦØąØ§ØĄ Ų…ØˇŲ„ŲˆØ¨</string>
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
Ø§Ų†Ų‚Øą ŲŲˆŲ‚ Ø˛Øą Ø§Ų„Ø§ØŗØĒŲ…ØąØ§Øą ŲˆØ§ØŗŲ…Ø­ بØĒØēŲŠŲŠØąØ§ØĒ Ø§Ų„ØĒØ­ØŗŲŠŲ†."</string> Ø§Ų†Ų‚Øą ŲŲˆŲ‚ Ø˛Øą Ø§Ų„Ø§ØŗØĒŲ…ØąØ§Øą ŲˆØ§ØŗŲ…Ø­ بØĒØēŲŠŲŠØąØ§ØĒ Ø§Ų„ØĒØ­ØŗŲŠŲ†."</string>
<string name="gms_core_dialog_continue_text">Ų…ØĒابؚ؊</string> <string name="gms_core_dialog_continue_text">Ų…ØĒابؚ؊</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Spoof Video Streams</string>
<string name="revanced_spoof_video_streams_screen_summary">ØĒØ˛ŲŠŲŠŲ ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ØŽØ§ØĩØŠ Ø¨Ø§Ų„ØšŲ…ŲŠŲ„ Ų„Ų…Ų†Øš Ø­Ø¯ŲˆØĢ Ų…Ø´ŲƒŲ„Ø§ØĒ ØŖØĢŲ†Ø§ØĄ Ø§Ų„ØĒØ´ØēŲŠŲ„</string>
<string name="revanced_spoof_video_streams_screen_title">Ø§Ų†ØĒØ­Ø§Ų„ بØĢ؈ØĢ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_spoof_video_streams_screen_summary">Ø§Ų†ØĒØ­Ø§Ų„ بØĢ؈ØĢ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ØŽØ§ØĩØŠ Ø¨Ø§Ų„ØšŲ…ŲŠŲ„ Ų„Ų…Ų†Øš Ų…Ø´ŲƒŲ„Ø§ØĒ Ø§Ų„ØĒØ´ØēŲŠŲ„</string>
<string name="revanced_spoof_video_streams_title">Spoof Video Streams</string>
<string name="revanced_spoof_video_streams_summary_on">"ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ų…Ø˛ŲˆØąØŠ
ØĨذا ŲƒŲ†ØĒ Ų…ØŗØĒØŽØ¯Ų…Ų‹Ø§ Ų„Ų€ YouTube Premium، ŲŲ‚Ø¯ Ų„Ø§ ŲŠŲƒŲˆŲ† Ų‡Ø°Ø§ Ø§Ų„ØĨؚداد Ų…ØˇŲ„ŲˆØ¨Ų‹Ø§"</string>
<string name="revanced_spoof_video_streams_summary_off">"Ų„Ų… ؊ØĒŲ… Ø§Ų†ØĒØ­Ø§Ų„ بØĢ؈ØĢ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ
Ų‚Ø¯ Ų„Ø§ ŲŠØšŲ…Ų„ Ø§Ų„ØĒØ´ØēŲŠŲ„"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">Ų‚Ø¯ ŲŠØ¤Ø¯ŲŠ ØĨŲŠŲ‚Ø§Ų ØĒØ´ØēŲŠŲ„ Ų‡Ø°Ø§ Ø§Ų„ØĨؚداد ØĨŲ„Ų‰ Ų…Ø´ŲƒŲ„Ø§ØĒ ؁؊ Ø§Ų„ØĒØ´ØēŲŠŲ„.</string>
<string name="revanced_spoof_video_streams_client_type_title">Ø§Ų„ØšŲ…ŲŠŲ„ Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_screen_summary">ØĒŲ…ŲƒŲŠŲ† ØŖŲˆ ØĒØšØˇŲŠŲ„ ØŽŲŠØ§ØąØ§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_title">ØĒØŗØŦŲŠŲ„ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† ØĒØŗØŦŲŠŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ ØĒØŗØŦŲŠŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_export_logs_to_clipboard_title">ØĒØĩØ¯ŲŠØą ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">Ų†ØŗØŽ ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ ØŖØŽØˇØ§ØĄ ReVanced ØĨŲ„Ų‰ Ø§Ų„Ø­Ø§ŲØ¸ØŠ</string>
<string name="revanced_debug_logs_disabled">ØĒŲ… ØĒØšØˇŲŠŲ„ ØĒØŗØŦŲŠŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_logs_none_found">Ų„Ų… ؊ØĒŲ… Ø§Ų„ØšØĢŲˆØą ØšŲ„Ų‰ ØŗØŦŲ„Ø§ØĒ</string>
<string name="revanced_debug_logs_copied_to_clipboard">ØĒŲ… Ų†ØŗØŽ Ø§Ų„ØŗØŦŲ„Ø§ØĒ</string>
<string name="revanced_debug_logs_failed_to_export">ŲØ´Ų„ ØĒØĩØ¯ŲŠØą Ø§Ų„ØŗØŦŲ„Ø§ØĒ: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">Ų…ØŗØ­ ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_logs_clear_buffer_summary">ŲŠŲ…ØŗØ­ ØŦŲ…ŲŠØš ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ ØŖØŽØˇØ§ØĄ ReVanced Ø§Ų„Ų…ØŽØ˛Ų†ØŠ</string>
<string name="revanced_debug_logs_clear_toast">ØĒŲ… Ų…ØŗØ­ Ø§Ų„ØŗØŦŲ„Ø§ØĒ</string>
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† ØĒØ´ØēŲŠŲ„ Shorts Ø¨Ø§Ų„ØŽŲ„ŲŲŠØŠ</string> <string name="revanced_shorts_disable_background_playback_summary_off">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† ØĒØ´ØēŲŠŲ„ Shorts Ø¨Ø§Ų„ØŽŲ„ŲŲŠØŠ</string>
</patch> </patch>
<patch id="misc.debugging.enableDebuggingPatch"> <patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_screen_summary">ØĒŲ…ŲƒŲŠŲ† ØŖŲˆ ØĒØšØˇŲŠŲ„ ØŽŲŠØ§ØąØ§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_title">ØĒØŗØŦŲŠŲ„ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† ØĒØŗØŦŲŠŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ ØĒØŗØŦŲŠŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_protobuffer_title">ØŗØŦŲ„ Ø¨ØąŲˆØĒŲˆŲƒŲˆŲ„ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string> <string name="revanced_debug_protobuffer_title">ØŗØŦŲ„ Ø¨ØąŲˆØĒŲˆŲƒŲˆŲ„ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string>
<string name="revanced_debug_protobuffer_summary_on">ØĒØĒØļŲ…Ų† ØŗØŦŲ„Ø§ØĒ Ø§Ų„ØĒØĩØ­ŲŠØ­ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string> <string name="revanced_debug_protobuffer_summary_on">ØĒØĒØļŲ…Ų† ØŗØŦŲ„Ø§ØĒ Ø§Ų„ØĒØĩØ­ŲŠØ­ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string>
<string name="revanced_debug_protobuffer_summary_off">Ų„Ø§ ØĒØĒØļŲ…Ų† ØŗØŦŲ„Ø§ØĒ Ø§Ų„ØĒØĩØ­ŲŠØ­ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string> <string name="revanced_debug_protobuffer_summary_off">Ų„Ø§ ØĒØĒØļŲ…Ų† ØŗØŦŲ„Ø§ØĒ Ø§Ų„ØĒØĩØ­ŲŠØ­ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string>
@@ -132,15 +160,6 @@ Second \"item\" text"</string>
<string name="revanced_debug_toast_on_error_user_dialog_message">"ŲŠØ¤Ø¯ŲŠ ØĨŲŠŲ‚Ø§Ų ØĒØ´ØēŲŠŲ„ Ų…Ų„Ø§Ø­Ø¸Ø§ØĒ Ø§Ų„ØŖØŽØˇØ§ØĄ ØĨŲ„Ų‰ ØĨØŽŲØ§ØĄ ŲƒØ§ŲØŠ ØĨØ´ØšØ§ØąØ§ØĒ ØŖØŽØˇØ§ØĄ ReVanced. <string name="revanced_debug_toast_on_error_user_dialog_message">"ŲŠØ¤Ø¯ŲŠ ØĨŲŠŲ‚Ø§Ų ØĒØ´ØēŲŠŲ„ Ų…Ų„Ø§Ø­Ø¸Ø§ØĒ Ø§Ų„ØŖØŽØˇØ§ØĄ ØĨŲ„Ų‰ ØĨØŽŲØ§ØĄ ŲƒØ§ŲØŠ ØĨØ´ØšØ§ØąØ§ØĒ ØŖØŽØˇØ§ØĄ ReVanced.
Ų„Ų† ؊ØĒŲ… ØĨØšŲ„Ø§Ų…Ųƒ Ø¨ØŖŲŠ ØŖØŽØˇØ§ØĄ ØēŲŠØą Ų…ØĒŲˆŲ‚ØšØŠ."</string> Ų„Ų† ؊ØĒŲ… ØĨØšŲ„Ø§Ų…Ųƒ Ø¨ØŖŲŠ ØŖØŽØˇØ§ØĄ ØēŲŠØą Ų…ØĒŲˆŲ‚ØšØŠ."</string>
<string name="revanced_debug_export_logs_to_clipboard_title">ØĒØĩØ¯ŲŠØą ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">Ų†ØŗØŽ ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ ØŖØŽØˇØ§ØĄ ReVanced ØĨŲ„Ų‰ Ø§Ų„Ø­Ø§ŲØ¸ØŠ</string>
<string name="revanced_debug_logs_disabled">ØĒŲ… ØĒØšØˇŲŠŲ„ ØĒØŗØŦŲŠŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_logs_none_found">Ų„Ų… ؊ØĒŲ… Ø§Ų„ØšØĢŲˆØą ØšŲ„Ų‰ ØŗØŦŲ„Ø§ØĒ</string>
<string name="revanced_debug_logs_copied_to_clipboard">ØĒŲ… Ų†ØŗØŽ Ø§Ų„ØŗØŦŲ„Ø§ØĒ</string>
<string name="revanced_debug_logs_failed_to_export">ŲØ´Ų„ ØĒØĩØ¯ŲŠØą Ø§Ų„ØŗØŦŲ„Ø§ØĒ: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">Ų…ØŗØ­ ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ Ø§Ų„ØŖØŽØˇØ§ØĄ</string>
<string name="revanced_debug_logs_clear_buffer_summary">ŲŠŲ…ØŗØ­ ØŦŲ…ŲŠØš ØŗØŦŲ„Ø§ØĒ ØĒØĩØ­ŲŠØ­ ØŖØŽØˇØ§ØĄ ReVanced Ø§Ų„Ų…ØŽØ˛Ų†ØŠ</string>
<string name="revanced_debug_logs_clear_toast">ØĒŲ… Ų…ØŗØ­ Ø§Ų„ØŗØŦŲ„Ø§ØĒ</string>
</patch> </patch>
<patch id="layout.hide.general.hideLayoutComponentsPatch"> <patch id="layout.hide.general.hideLayoutComponentsPatch">
<string name="revanced_hide_album_cards_title">ØĨØŽŲØ§ØĄ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ØŖŲ„Ø¨ŲˆŲ…</string> <string name="revanced_hide_album_cards_title">ØĨØŽŲØ§ØĄ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ØŖŲ„Ø¨ŲˆŲ…</string>
@@ -602,6 +621,10 @@ Second \"item\" text"</string>
<string name="revanced_hide_clip_button_title">ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ų‚ØˇØš</string> <string name="revanced_hide_clip_button_title">ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ų‚ØˇØš</string>
<string name="revanced_hide_clip_button_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø˛Øą ØĨŲ†Ø´Ø§ØĄ Ų…Ų‚ØˇØš</string> <string name="revanced_hide_clip_button_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø˛Øą ØĨŲ†Ø´Ø§ØĄ Ų…Ų‚ØˇØš</string>
<string name="revanced_hide_clip_button_summary_off">؊ØĒŲ… ØšØąØļ Ø˛Øą ØĨŲ†Ø´Ø§ØĄ Ų…Ų‚ØˇØš</string> <string name="revanced_hide_clip_button_summary_off">؊ØĒŲ… ØšØąØļ Ø˛Øą ØĨŲ†Ø´Ø§ØĄ Ų…Ų‚ØˇØš</string>
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_shop_button_title">ØĨØŽŲØ§ØĄ Ø§Ų„Ų…ØĒØŦØą</string>
<string name="revanced_hide_shop_button_summary_on">Ø˛Øą Ø§Ų„Ų…ØĒØŦØą Ų…ØŽŲŲŠ</string>
<string name="revanced_hide_shop_button_summary_off">Ø˛Øą Ø§Ų„Ų…ØĒØŦØą Ų…ØšØąŲˆØļ</string>
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_save_button_title">ØĨØŽŲØ§ØĄ Ø­ŲØ¸</string> <string name="revanced_hide_save_button_title">ØĨØŽŲØ§ØĄ Ø­ŲØ¸</string>
<string name="revanced_hide_save_button_summary_on">Ø˛Øą Ø§Ų„Ø­ŲØ¸ Ų…ØŽŲŲŠ</string> <string name="revanced_hide_save_button_summary_on">Ø˛Øą Ø§Ų„Ø­ŲØ¸ Ų…ØŽŲŲŠ</string>
@@ -700,9 +723,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_player_flyout_audio_track_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊</string> <string name="revanced_hide_player_flyout_audio_track_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊</string>
<string name="revanced_hide_player_flyout_audio_track_summary_off">؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊</string> <string name="revanced_hide_player_flyout_audio_track_summary_off">؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_hide_player_flyout_audio_track_not_available">"ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊ <string name="revanced_hide_player_flyout_audio_track_not_available">"Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…ØŗØ§ØąØ§ØĒ Ø§Ų„Øĩ؈ØĒŲŠØŠ Ų…ØŽŲŲŠØŠ
Ų„ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒŲŠØŒ ØēŲŠŲ‘Øą 'Spoof Video Streams' ØĨŲ„Ų‰ iOS TV"</string> Ų„ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…ØŗØ§ØąØ§ØĒ Ø§Ų„Øĩ؈ØĒŲŠØŠØŒ ØēŲŠŲ‘Øą 'ØĒØ˛ŲŠŲŠŲ ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ' ØĨŲ„Ų‰ iPadOS"</string>
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. --> <!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ ؁؊ VR</string> <string name="revanced_hide_player_flyout_watch_in_vr_title">ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ ؁؊ VR</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ ؁؊ Ø§Ų„ŲˆØļØš Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string> <string name="revanced_hide_player_flyout_watch_in_vr_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ ؁؊ Ø§Ų„ŲˆØļØš Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
@@ -1415,10 +1438,6 @@ Second \"item\" text"</string>
ŲŠŲ…ŲƒŲ† ØŖŲ† ŲŠØ¤Ø¯ŲŠ ØĒŲØšŲŠŲ„ Ų‡Ø°Ø§ ØĨŲ„Ų‰ ؁ØĒØ­ ØŦŲˆØ¯ØŠ ØŖØšŲ„Ų‰ Ų„Ų„ŲŲŠØ¯ŲŠŲˆ"</string> ŲŠŲ…ŲƒŲ† ØŖŲ† ŲŠØ¤Ø¯ŲŠ ØĒŲØšŲŠŲ„ Ų‡Ø°Ø§ ØĨŲ„Ų‰ ؁ØĒØ­ ØŦŲˆØ¯ØŠ ØŖØšŲ„Ų‰ Ų„Ų„ŲŲŠØ¯ŲŠŲˆ"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">Ų‚Ø¯ ŲŠØ¤Ø¯ŲŠ ØĒŲ…ŲƒŲŠŲ† Ų‡Ø°Ø§ ØĨŲ„Ų‰ ØĒØ¨Ø§ØˇØ¤ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ ؈ØĒØ¯Ų‡ŲˆØą ØšŲ…Øą Ø§Ų„Ø¨ØˇØ§ØąŲŠØŠ ؈ØĸØĢØ§Øą ØŦØ§Ų†Ø¨ŲŠØŠ ØēŲŠØą Ų…ØšØąŲˆŲØŠ.</string> <string name="revanced_spoof_device_dimensions_user_dialog_message">Ų‚Ø¯ ŲŠØ¤Ø¯ŲŠ ØĒŲ…ŲƒŲŠŲ† Ų‡Ø°Ø§ ØĨŲ„Ų‰ ØĒØ¨Ø§ØˇØ¤ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ ؈ØĒØ¯Ų‡ŲˆØą ØšŲ…Øą Ø§Ų„Ø¨ØˇØ§ØąŲŠØŠ ؈ØĸØĢØ§Øą ØŦØ§Ų†Ø¨ŲŠØŠ ØēŲŠØą Ų…ØšØąŲˆŲØŠ.</string>
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">ØĨؚداداØĒ GmsCore</string>
<string name="microg_settings_summary">ØĨؚداداØĒ Ų„Ų€ GmsCore</string>
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
<string name="revanced_disable_haptic_feedback_title">Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string> <string name="revanced_disable_haptic_feedback_title">Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string>
<string name="revanced_disable_haptic_feedback_summary">ØĒØēŲŠŲŠØą Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string> <string name="revanced_disable_haptic_feedback_summary">ØĒØēŲŠŲŠØą Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string>
@@ -1458,7 +1477,7 @@ Second \"item\" text"</string>
<string name="revanced_force_original_audio_summary_on">Ø§ØŗØĒØŽØ¯Ø§Ų… Ų„ØēØŠ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØŖØĩŲ„ŲŠØŠ</string> <string name="revanced_force_original_audio_summary_on">Ø§ØŗØĒØŽØ¯Ø§Ų… Ų„ØēØŠ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØŖØĩŲ„ŲŠØŠ</string>
<string name="revanced_force_original_audio_summary_off">Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„Øĩ؈ØĒ Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string> <string name="revanced_force_original_audio_summary_off">Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„Øĩ؈ØĒ Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">Ų„Ø§ØŗØĒØŽØ¯Ø§Ų… Ų‡Ø°Ų‡ Ø§Ų„Ų…ŲŠØ˛ØŠØŒ ØēŲŠŲ‘Øą \'Spoof Video Streams\' ØĨŲ„Ų‰ iOS TV</string> <string name="revanced_force_original_audio_not_available">Ų„Ø§ØŗØĒØŽØ¯Ø§Ų… Ų‡Ø°Ų‡ Ø§Ų„Ų…ŲŠØ˛ØŠØŒ ØēŲŠŲ‘Øą \"ØĒØ˛ŲˆŲŠØą ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ\" ØĨŲ„Ų‰ ØŖŲŠ ØšŲ…ŲŠŲ„ Ø¨Ø§ØŗØĒØĢŲ†Ø§ØĄ Android Studio</string>
</patch> </patch>
<patch id="video.quality.rememberVideoQualityPatch"> <patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. --> <!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1532,35 +1551,54 @@ Second \"item\" text"</string>
<string name="revanced_slide_to_seek_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„ØĒŲ…ØąŲŠØą Ų„Ų„ØĒŲ‚Ø¯ŲŠŲ… ØŖŲˆ Ø§Ų„ØĒØąØŦŲŠØš</string> <string name="revanced_slide_to_seek_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„ØĒŲ…ØąŲŠØą Ų„Ų„ØĒŲ‚Ø¯ŲŠŲ… ØŖŲˆ Ø§Ų„ØĒØąØŦŲŠØš</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Spoof Video Streams</string> <string name="revanced_spoof_video_streams_about_title">Ø§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų„ØĒØ˛ŲˆŲŠØą</string>
<string name="revanced_spoof_video_streams_screen_summary">ØĒØ˛ŲŠŲŠŲ ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ØŽØ§ØĩØŠ Ø¨Ø§Ų„ØšŲ…ŲŠŲ„ Ų„Ų…Ų†Øš Ø­Ø¯ŲˆØĢ Ų…Ø´ŲƒŲ„Ø§ØĒ ØŖØĢŲ†Ø§ØĄ Ø§Ų„ØĒØ´ØēŲŠŲ„</string>
<string name="revanced_spoof_video_streams_title">Spoof Video Streams</string>
<string name="revanced_spoof_video_streams_summary_on">؊ØĒŲ… ØĒØ˛ŲŠŲŠŲ ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_spoof_video_streams_summary_off">"Ų„Ø§ ؊ØĒŲ… ØĒØ˛ŲŠŲŠŲ ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ
Ų‚Ø¯ Ų„Ø§ ŲŠØšŲ…Ų„ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">ØĨŲŠŲ‚Ø§Ų ØĒØ´ØēŲŠŲ„ Ų‡Ø°Ø§ Ø§Ų„ØĨؚداد Ų‚Ø¯ ŲŠØŗØ¨Ø¨ Ų…Ø´Ø§ŲƒŲ„ ؁؊ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ.</string>
<string name="revanced_spoof_video_streams_client_type_title">Ø§Ų„ØšŲ…ŲŠŲ„ Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
<string name="revanced_spoof_video_streams_ios_force_avc_title">ŲØąØļ iOS AVC (H.264)</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">؊ØĒŲ… ŲØąØļ ØĒØąŲ…ŲŠØ˛ ŲŲŠØ¯ŲŠŲˆ ØšŲ„Ų‰ AVC (H.264)</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">؊ØĒŲ… ØĒØ­Ø¯ŲŠØ¯ ØĒØąŲ…ŲŠØ˛ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ ØĒŲ„Ų‚Ø§ØĻŲŠŲ‹Ø§</string>
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"Ų‚Ø¯ ŲŠØ¤Ø¯ŲŠ ØĒŲ…ŲƒŲŠŲ† Ų‡Ø°Ø§ ØĨŲ„Ų‰ ØĒØ­ØŗŲŠŲ† ØšŲ…Øą Ø§Ų„Ø¨ØˇØ§ØąŲŠØŠ ؈ØĨØĩŲ„Ø§Ø­ ØĒŲ‚ØˇŲŠØš Ø§Ų„ØĒØ´ØēŲŠŲ„.
AVC Ų„Ø¯ŲŠŲ‡ حد ØŖŲ‚ØĩŲ‰ Ų„Ų„Ø¯Ų‚ØŠ 1080p، Ų„Ø§ ؊ØĒŲˆŲØą ØĒØąŲ…ŲŠØ˛ Ø§Ų„Øĩ؈ØĒ Opus، ŲˆØŗŲˆŲ ŲŠØŗØĒØŽØ¯Ų… ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø¨ŲŠØ§Ų†Ø§ØĒ ØĨŲ†ØĒØąŲ†ØĒ ØŖŲƒØĢØą Ų…Ų† VP9 ØŖŲˆ AV1."</string>
<string name="revanced_spoof_video_streams_about_ios_tv_title">Ø§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų…Ø­Ø§ŲƒØ§ØŠ Ų‡ŲˆŲŠØŠ iOS</string>
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"â€ĸ Ų‚Ø¯ Ų„Ø§ ؊ØĒŲ… ØĒØ´ØēŲŠŲ„ Ø§Ų„ØŖŲŲ„Ø§Ų… ØŖŲˆ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Ø§Ų„Ų…Ø¯ŲŲˆØšØŠ
â€ĸ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØĢابØĒ ØēŲŠØą Ų…ØĒŲˆŲØą
â€ĸ ØĒŲ†ØĒŲ‡ŲŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Ų‚Ø¨Ų„ ب 1 ØĢØ§Ų†ŲŠØŠ"</string>
<string name="revanced_spoof_video_streams_about_android_title">Ø§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų…Ø­Ø§ŲƒØ§ØŠ Ų‡ŲˆŲŠØŠ Android</string> <string name="revanced_spoof_video_streams_about_android_title">Ø§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų…Ø­Ø§ŲƒØ§ØŠ Ų‡ŲˆŲŠØŠ Android</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊ Ų…ŲŲ‚ŲˆØ¯ØŠ <string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…ØŗØ§ØąØ§ØĒ Ø§Ų„Øĩ؈ØĒŲŠØŠ Ų…ŲŲ‚ŲˆØ¯ØŠ
â€ĸ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØĢابØĒ ØēŲŠØą Ų…ØĒاح â€ĸ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ Ø§Ų„Ų…ØŗØĒŲ‚Øą ØēŲŠØą Ų…ØĒاح"</string>
â€ĸ ŲØąØļ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØŖØĩŲ„ŲŠ ØēŲŠØą Ų…ØĒŲˆŲØą"</string> <string name="revanced_spoof_video_streams_about_ipados_summary">â€ĸ Ų‚Ø¯ ؊ØĒŲˆŲ‚Ų Ø§Ų„ŲŲŠØ¯ŲŠŲˆ ØšŲ†Ø¯ 1:00، ØŖŲˆ Ų‚Ø¯ Ų„Ø§ ŲŠŲƒŲˆŲ† Ų…ØĒØ§Ø­Ų‹Ø§ ؁؊ بؚØļ Ø§Ų„Ų…Ų†Ø§ØˇŲ‚</string>
<string name="revanced_spoof_video_streams_about_experimental">â€ĸ ØšŲ…ŲŠŲ„ ØĒØŦØąŲŠØ¨ŲŠ ŲˆŲ‚Ø¯ ؊ØĒŲˆŲ‚Ų ØšŲ† Ø§Ų„ØšŲ…Ų„ ؁؊ ØŖŲŠ ŲˆŲ‚ØĒ</string>
<string name="revanced_spoof_video_streams_about_no_av1">â€ĸ Ų„Ø§ ؊؈ØŦد ØĒØąŲ…ŲŠØ˛ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ AV1</string> <string name="revanced_spoof_video_streams_about_no_av1">â€ĸ Ų„Ø§ ؊؈ØŦد ØĒØąŲ…ŲŠØ˛ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ AV1</string>
<string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ Ų‚Ø¯ Ų„Ø§ ؊ØĒŲ… ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Ø§Ų„Ų…ØŽØĩØĩØŠ Ų„Ų„ØŖØˇŲØ§Ų„ ØšŲ†Ø¯ ØĒØŗØŦŲŠŲ„ Ø§Ų„ØŽØąŲˆØŦ ØŖŲˆ ØšŲ†Ø¯ Ø§ØŗØĒØŽØ¯Ø§Ų… ؈ØļØš Ø§Ų„ØĒØĩŲØ­ Ø§Ų„Ų…ØĒØŽŲŲŠ</string> <string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ Ų‚Ø¯ Ų„Ø§ ؊ØĒŲ… ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Ø§Ų„Ų…ØŽØĩØĩØŠ Ų„Ų„ØŖØˇŲØ§Ų„ ØšŲ†Ø¯ ØĒØŗØŦŲŠŲ„ Ø§Ų„ØŽØąŲˆØŦ ØŖŲˆ ØšŲ†Ø¯ Ø§ØŗØĒØŽØ¯Ø§Ų… ؈ØļØš Ø§Ų„ØĒØĩŲØ­ Ø§Ų„Ų…ØĒØŽŲŲŠ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">ØšØąØļ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">ØšØąØļ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">؊ØĒŲ… ØšØąØļ Ų†ŲˆØš Ø§Ų„ØšŲ…ŲŠŲ„ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">؊ØĒŲ… ØšØąØļ Ų†ŲˆØš Ø§Ų„ØšŲ…ŲŠŲ„ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">ØĒŲ… ØĨØŽŲØ§ØĄ Ų†ŲˆØš Ø§Ų„ØšŲ…ŲŠŲ„ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">ØĒŲ… ØĨØŽŲØ§ØĄ Ų†ŲˆØš Ø§Ų„ØšŲ…ŲŠŲ„ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string>
<string name="revanced_spoof_video_streams_language_title">Ų„ØēØŠ Ø§Ų„Ø¨ØĢ Ø§Ų„Øĩ؈ØĒ؊ Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ Ų„Ų„ŲˆØ§Ų‚Øš Ø§Ų„Ø§ŲØĒØąØ§Øļ؊ VR</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>
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
<string name="revanced_settings_music_screen_0_about_title">Ø­ŲˆŲ„</string>
<string name="revanced_settings_music_screen_1_ads_title">ØĨØšŲ„Ø§Ų†Ø§ØĒ</string>
<string name="revanced_settings_music_screen_2_general_title">ØšØ§Ų…</string>
<string name="revanced_settings_music_screen_3_player_title">Ø§Ų„Ų…Ø´ØēŲ„</string>
<string name="revanced_settings_music_screen_4_misc_title">Ų…ØĒŲ†ŲˆØšØŠ</string>
</patch>
<patch id="ad.video.hideVideoAdsPatch">
<string name="revanced_music_hide_video_ads_title">ØĨØŽŲØ§ØĄ ØĨØšŲ„Ø§Ų†Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_music_hide_video_ads_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ ØĨØšŲ„Ø§Ų†Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_music_hide_video_ads_summary_off">ØĒŲ… ØšØąØļ ØĨØšŲ„Ø§Ų†Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
<string name="revanced_music_play_permanent_repeat_title">ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØĒŲƒØąØ§Øą Ø§Ų„Ø¯Ø§ØĻŲ…</string>
<string name="revanced_music_play_permanent_repeat_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØĒŲƒØąØ§Øą Ø§Ų„Ø¯Ø§ØĻŲ…</string>
<string name="revanced_music_play_permanent_repeat_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„ØĒŲƒØąØ§Øą Ø§Ų„Ø¯Ø§ØĻŲ…</string>
</patch>
<patch id="layout.compactheader.hideCategoryBar">
<string name="revanced_music_hide_category_bar_title">ØĨØŽŲØ§ØĄ Ø´ØąŲŠØˇ Ø§Ų„ŲØĻاØĒ</string>
<string name="revanced_music_hide_category_bar_summary_on">Ø´ØąŲŠØˇ Ø§Ų„ŲØĻاØĒ Ų…ØŽŲŲŠ</string>
<string name="revanced_music_hide_category_bar_summary_off">Ø´ØąŲŠØˇ Ø§Ų„ŲØĻاØĒ Ų…ØšØąŲˆØļ</string>
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title">ØĨØŽŲØ§ØĄ ØĒØŗŲ…ŲŠØŠ \'Ø§Ų„Ø­ØĩŲˆŲ„ ØšŲ„Ų‰ Music Premium\'</string>
<string name="revanced_music_hide_get_premium_label_summary_on">Ø§Ų„ØĒØŗŲ…ŲŠØŠ Ų…ØŽŲŲŠØŠ</string>
<string name="revanced_music_hide_get_premium_label_summary_off">Ø§Ų„ØĒØŗŲ…ŲŠØŠ Ų…ØšØąŲˆØļØŠ</string>
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
<string name="revanced_music_hide_upgrade_button_title">ØĨØŽŲØ§ØĄ Ø˛Øą Ø§Ų„ØĒØąŲ‚ŲŠØŠ</string>
<string name="revanced_music_hide_upgrade_button_summary_on">Ø§Ų„Ø˛Øą Ų…ØŽŲŲŠ</string>
<string name="revanced_music_hide_upgrade_button_summary_off">Ø§Ų„Ø˛Øą Ų…ØšØąŲˆØļ</string>
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -30,6 +30,10 @@ Second \"item\" text"</string>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -96,6 +100,7 @@ Second \"item\" text"</string>
<!-- 'Ask' should be translated with the same localized wording that YouTube displays. <!-- 'Ask' should be translated with the same localized wording that YouTube displays.
This button only shows if the user ip is from specific region such as the USA or EU. --> This button only shows if the user ip is from specific region such as the USA or EU. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. --> <!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch> </patch>
<patch id="layout.buttons.navigation.navigationButtonsPatch"> <patch id="layout.buttons.navigation.navigationButtonsPatch">
@@ -209,8 +214,6 @@ Second \"item\" text"</string>
</patch> </patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch"> <patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
</patch> </patch>
<patch id="misc.gms.accountCredentialsInvalidTextPatch"> <patch id="misc.gms.accountCredentialsInvalidTextPatch">
@@ -242,6 +245,21 @@ Second \"item\" text"</string>
<patch id="interaction.seekbar.enableSlideToSeekPatch"> <patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<!-- 'Force original audio language' should use the same text as revanced_force_original_audio_title -->
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
</patch>
<patch id="ad.video.hideVideoAdsPatch">
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
</patch>
<patch id="layout.compactheader.hideCategoryBar">
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -68,6 +68,8 @@ Yeni dilləri tərcÃŧmə etmək ÃŧçÃŧn translate.revanced.app 'ə daxil olun"</
and changes made here must also be made there. --> and changes made here must also be made there. -->
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore Tənzimləmələri</string>
<string name="microg_settings_summary">GmsCore ÃŧçÃŧn Tənzimləmələr</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="gms_core_toast_not_installed_message">MicroG GmsCore quraşdÄąrÄąlmayÄąb. Bunu quraşdÄąr.</string> <string name="gms_core_toast_not_installed_message">MicroG GmsCore quraşdÄąrÄąlmayÄąb. Bunu quraşdÄąr.</string>
<string name="gms_core_dialog_title">Fəaliyyət lazımdır</string> <string name="gms_core_dialog_title">Fəaliyyət lazımdır</string>
@@ -84,6 +86,37 @@ MicroG ÃŧçÃŧn batareya optimallaşmasÄąn qapatma batareya istifadəsinə mənfi
Davam et dÃŧyməsinə toxun və optimallaşdÄąrma dəyişikliklərin qəbul et."</string> Davam et dÃŧyməsinə toxun və optimallaşdÄąrma dəyişikliklərin qəbul et."</string>
<string name="gms_core_dialog_continue_text">Davam et</string> <string name="gms_core_dialog_continue_text">Davam et</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Video yayÄąmlarÄą saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_screen_summary">Oynatma problemlərin Ãļnləmək ÃŧçÃŧn qəbuledici video yayÄąmlarÄąn saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_screen_title">Video yayÄąmlarÄąn saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_screen_summary">Oynatma problemlərin Ãļnləmək ÃŧçÃŧn qəbuledici video yayÄąmlarÄąn saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_title">Video yayÄąmlarÄą saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_summary_on">"Video yayÄąmlarÄą saxtalaşdÄąrÄąlÄąb
Əgər YouTube Premium istifadəçisisinizsə, bu tənzimlənmə tələb olunmaya bilər"</string>
<string name="revanced_spoof_video_streams_summary_off">"Video yayÄąmlarÄą saxtalaşmayÄąb
Oynatma işləməyə bilər"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">Bu tənzimləməni qapatmaq oynatma problemlərinə səbəb ola bilər.</string>
<string name="revanced_spoof_video_streams_client_type_title">İlkin qəbuledici</string>
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">Sazlama</string>
<string name="revanced_debug_screen_summary">Sazlama seçimlərini aktiv/qeyri-aktiv et</string>
<string name="revanced_debug_title">Sazlama jurnalÄą</string>
<string name="revanced_debug_summary_on">Sazlama jurnalÄą işləkdir</string>
<string name="revanced_debug_summary_off">Sazlama jurnalÄą qeyri-aktivdir</string>
<string name="revanced_debug_export_logs_to_clipboard_title">Sazlama qeydlərini ixrac edin</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">ReVanced sazlama qeydlərini buferə kÃļçÃŧrÃŧr</string>
<string name="revanced_debug_logs_disabled">Sazlama qeydi qapalÄądÄąr</string>
<string name="revanced_debug_logs_none_found">Qeydlər tapılmadı</string>
<string name="revanced_debug_logs_copied_to_clipboard">Qeydlər kÃļçÃŧrÃŧldÃŧ</string>
<string name="revanced_debug_logs_failed_to_export">Qeydləri ixrac etmək alınmadı: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">Sazlama qeydlərini təmizlə</string>
<string name="revanced_debug_logs_clear_buffer_summary">SaxlanÄąlan bÃŧtÃŧn ReVanced sazlama qeydlərini təmizləyir</string>
<string name="revanced_debug_logs_clear_toast">Qeydlər silindi</string>
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Davam et dÃŧyməsinə toxun və optimallaşdÄąrma dəyişikliklərin qəbul et."
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts arxa plan oynatma aktivdir</string> <string name="revanced_shorts_disable_background_playback_summary_off">Shorts arxa plan oynatma aktivdir</string>
</patch> </patch>
<patch id="misc.debugging.enableDebuggingPatch"> <patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">Sazlama</string>
<string name="revanced_debug_screen_summary">Sazlama seçimlərini aktiv/qeyri-aktiv et</string>
<string name="revanced_debug_title">Sazlama jurnalÄą</string>
<string name="revanced_debug_summary_on">Sazlama jurnalÄą işləkdir</string>
<string name="revanced_debug_summary_off">Sazlama jurnalÄą qeyri-aktivdir</string>
<string name="revanced_debug_protobuffer_title">Bufer protokol jurnalÄą</string> <string name="revanced_debug_protobuffer_title">Bufer protokol jurnalÄą</string>
<string name="revanced_debug_protobuffer_summary_on">Sazlama jurnallarÄąna protokol buferi daxildir</string> <string name="revanced_debug_protobuffer_summary_on">Sazlama jurnallarÄąna protokol buferi daxildir</string>
<string name="revanced_debug_protobuffer_summary_off">Sazlama jurnallarÄąna protokol buferi daxil deyil</string> <string name="revanced_debug_protobuffer_summary_off">Sazlama jurnallarÄąna protokol buferi daxil deyil</string>
@@ -132,15 +160,6 @@ Hər halda, bunu aktivləşdirmə IP ÃŧnvanÄąnÄąz kimi bəzi istifadəçi məlum
<string name="revanced_debug_toast_on_error_user_dialog_message">"Xəta ani bildirişlərin qapatmaq, bÃŧtÃŧn ReVanced xəta bildirişlərin gizlədir. <string name="revanced_debug_toast_on_error_user_dialog_message">"Xəta ani bildirişlərin qapatmaq, bÃŧtÃŧn ReVanced xəta bildirişlərin gizlədir.
GÃļzlənilməz hallardan xəbərdar olmayacaqsÄąnÄąz."</string> GÃļzlənilməz hallardan xəbərdar olmayacaqsÄąnÄąz."</string>
<string name="revanced_debug_export_logs_to_clipboard_title">Sazlama qeydlərini ixrac edin</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">ReVanced sazlama qeydlərini buferə kÃļçÃŧrÃŧr</string>
<string name="revanced_debug_logs_disabled">Sazlama qeydi qapalÄądÄąr</string>
<string name="revanced_debug_logs_none_found">Qeydlər tapılmadı</string>
<string name="revanced_debug_logs_copied_to_clipboard">Qeydlər kÃļçÃŧrÃŧldÃŧ</string>
<string name="revanced_debug_logs_failed_to_export">Qeydləri ixrac etmək alınmadı: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">Sazlama qeydlərini təmizlə</string>
<string name="revanced_debug_logs_clear_buffer_summary">SaxlanÄąlan bÃŧtÃŧn ReVanced sazlama qeydlərini təmizləyir</string>
<string name="revanced_debug_logs_clear_toast">Qeydlər silindi</string>
</patch> </patch>
<patch id="layout.hide.general.hideLayoutComponentsPatch"> <patch id="layout.hide.general.hideLayoutComponentsPatch">
<string name="revanced_hide_album_cards_title">Albom kartlarını gizlət</string> <string name="revanced_hide_album_cards_title">Albom kartlarını gizlət</string>
@@ -602,6 +621,10 @@ EkranÄąn sağ tərəfində dÃŧzÃŧnə sÃŧrÃŧşdÃŧrərək səs səviyyəsini tənz
<string name="revanced_hide_clip_button_title">Kəsmə/ gizlət</string> <string name="revanced_hide_clip_button_title">Kəsmə/ gizlət</string>
<string name="revanced_hide_clip_button_summary_on">Kəsmə dÃŧyməsi gizlidir</string> <string name="revanced_hide_clip_button_summary_on">Kəsmə dÃŧyməsi gizlidir</string>
<string name="revanced_hide_clip_button_summary_off">Kəsmə dÃŧyməsi gÃļstərilir</string> <string name="revanced_hide_clip_button_summary_off">Kəsmə dÃŧyməsi gÃļstərilir</string>
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_shop_button_title">Mağazanı Gizlət</string>
<string name="revanced_hide_shop_button_summary_on">Mağaza dÃŧyməsi gizlidir</string>
<string name="revanced_hide_shop_button_summary_off">Mağaza dÃŧyməsi gÃļrÃŧnÃŧr</string>
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_save_button_title">Saxlayın-ı Gizlət</string> <string name="revanced_hide_save_button_title">Saxlayın-ı Gizlət</string>
<string name="revanced_hide_save_button_summary_on">SaxlayÄąn dÃŧyməsi gizlidir</string> <string name="revanced_hide_save_button_summary_on">SaxlayÄąn dÃŧyməsi gizlidir</string>
@@ -700,9 +723,9 @@ Bu seçimi dəyişdirmə işə dÃŧşmÃŧrsə, Gizli rejimə keçməyə çalÄąÅŸÄą
<string name="revanced_hide_player_flyout_audio_track_summary_on">Səs axını menyusu gizlidir</string> <string name="revanced_hide_player_flyout_audio_track_summary_on">Səs axını menyusu gizlidir</string>
<string name="revanced_hide_player_flyout_audio_track_summary_off">Səs axÄąnÄą menyusu gÃļstərilir</string> <string name="revanced_hide_player_flyout_audio_track_summary_off">Səs axÄąnÄą menyusu gÃļstərilir</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_hide_player_flyout_audio_track_not_available">"Audio trek seçimi gizlədilib <string name="revanced_hide_player_flyout_audio_track_not_available">"Səs trek menyusu gizlidir
Audio trek seçimin gÃļstərmək ÃŧçÃŧn \"Video axÄąnlarÄą saxtalaşdÄąr\"Äą iOS TV-yə dəyiş"</string> Səs treki menyusunu gÃļstərmək ÃŧçÃŧn \"Video yayÄąmlarÄą saxtalaşdÄąr\"Äą iPadOS-a dəyiş"</string>
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. --> <!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">\"VR-da İzləni\" gizlət</string> <string name="revanced_hide_player_flyout_watch_in_vr_title">\"VR-da İzləni\" gizlət</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">VR menyusunda izləmə gizlidir</string> <string name="revanced_hide_player_flyout_watch_in_vr_summary_on">VR menyusunda izləmə gizlidir</string>
@@ -1414,10 +1437,6 @@ YÃŧksək video keyfiyyətlər gÃļrÃŧnə bilər, ancaq video oynadÄąlmasÄąnda qÄą
Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər"</string> Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">Bunu aktivləşdirmə, video oynatma donmalarÄąna, daha pis batareya istismarÄąna və bilinməyən yan təsirlərə səbəb ola bilər.</string> <string name="revanced_spoof_device_dimensions_user_dialog_message">Bunu aktivləşdirmə, video oynatma donmalarÄąna, daha pis batareya istismarÄąna və bilinməyən yan təsirlərə səbəb ola bilər.</string>
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore Tənzimləmələri</string>
<string name="microg_settings_summary">GmsCore ÃŧçÃŧn Tənzimləmələr</string>
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
<string name="revanced_disable_haptic_feedback_title">Əks-əlaqə reaksiyasÄą</string> <string name="revanced_disable_haptic_feedback_title">Əks-əlaqə reaksiyasÄą</string>
<string name="revanced_disable_haptic_feedback_summary">Əks-əlaqə reaksiyasÄąnÄą dəyişdir</string> <string name="revanced_disable_haptic_feedback_summary">Əks-əlaqə reaksiyasÄąnÄą dəyişdir</string>
@@ -1457,7 +1476,7 @@ Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər
<string name="revanced_force_original_audio_summary_on">Orijinal səs dilini istifadə</string> <string name="revanced_force_original_audio_summary_on">Orijinal səs dilini istifadə</string>
<string name="revanced_force_original_audio_summary_off">İlkin səs istifadəsi</string> <string name="revanced_force_original_audio_summary_off">İlkin səs istifadəsi</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">Bu xÃŧsusiyyəti istifadə etmək ÃŧçÃŧn \"Saxta video yayÄąmlarÄąn\" iOS TV-yə dəyiş</string> <string name="revanced_force_original_audio_not_available">Bu funksiyanÄą istifadə etmək ÃŧçÃŧn \"Video yayÄąmlarÄą saxtalaşdÄąrÄą\" Android Studio savayÄą istənilən qəbulediciyə dəyiş</string>
</patch> </patch>
<patch id="video.quality.rememberVideoQualityPatch"> <patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. --> <!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1531,35 +1550,54 @@ Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər
<string name="revanced_slide_to_seek_summary_off">Axtarmaq ÃŧçÃŧn sÃŧrÃŧşdÃŧrmə aktiv deyil</string> <string name="revanced_slide_to_seek_summary_off">Axtarmaq ÃŧçÃŧn sÃŧrÃŧşdÃŧrmə aktiv deyil</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Video yayÄąmlarÄą saxtalaşdÄąr</string> <string name="revanced_spoof_video_streams_about_title">SaxtakarlÄąq yan təsirləri</string>
<string name="revanced_spoof_video_streams_screen_summary">Oynatma problemlərin Ãļnləmək ÃŧçÃŧn qəbuledici video yayÄąmlarÄąn saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_title">Video yayÄąmlarÄą saxtalaşdÄąr</string>
<string name="revanced_spoof_video_streams_summary_on">Video yayÄąmlarÄą saxtalaşdÄąrÄąlÄąr</string>
<string name="revanced_spoof_video_streams_summary_off">"Video yayÄąmlar saxtalaşdÄąrÄąlmÄąr
Video oynatma işləməyə bilər"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">Bu seçimi bağlamaq, video oynatma problemlərinə səbəb olar.</string>
<string name="revanced_spoof_video_streams_client_type_title">İlkin qəbuledici</string>
<string name="revanced_spoof_video_streams_ios_force_avc_title">IOS-da AVC (H.264)-ni məcbur et</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">Video kodlama AVC (H.264)-yə məcbur edilir</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">Video kodlayÄącÄą avtomatik mÃŧəyyən edilir</string>
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"Bunu aktivləşdirmə, batareya ÃļmrÃŧn yaxÅŸÄąlaşdÄąra və oynatma qÄąrÄąlmasÄąn dÃŧzəldə bilər.
AVC maksimum 1080p gÃļrÃŧntÃŧ imkanÄąna malikdir, Opus audio kodlama olmur və video oynatma VP9 və ya AV1-dən daha çox internet məlumatÄą sərf edəcək."</string>
<string name="revanced_spoof_video_streams_about_ios_tv_title">iOS saxtalaşdÄąrma yan təsirləri</string>
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"â€ĸ Filmlər və ya Ãļdənişli videolar oynadÄąla bilməz
â€ĸ Stabil səs səviyyəsi mÃļvcud deyil
â€ĸ Videolar 1 saniyə tez bitir"</string>
<string name="revanced_spoof_video_streams_about_android_title">Android saxtalaşdÄąrma yan təsirləri</string> <string name="revanced_spoof_video_streams_about_android_title">Android saxtalaşdÄąrma yan təsirləri</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Səs treki menyusu yoxdur <string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Səs treki menyusu əlçatmazdÄąr
â€ĸ Sabit səs səviyyəsi yoxdur â€ĸ Sabit səs səviyyəsi yoxdur"</string>
â€ĸ İlkin səsi məcbur etmə mÃŧmkÃŧn deyil"</string> <string name="revanced_spoof_video_streams_about_ipados_summary">â€ĸ Video 01:00-da dayana bilər və ya bəzi bÃļlgələrdə mÃļvcud olmaya bilər</string>
<string name="revanced_spoof_video_streams_about_experimental">â€ĸ TəcrÃŧbi qəbuledici və hər vaxt işləməyi dayandÄąra bilər</string>
<string name="revanced_spoof_video_streams_about_no_av1">â€ĸ AV1 video kodlayÄącÄą yoxdur</string> <string name="revanced_spoof_video_streams_about_no_av1">â€ĸ AV1 video kodlayÄącÄą yoxdur</string>
<string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ Giriş edilməyəndə və ya gizli rejimdə uşaq videolarÄą oynadÄąla bilməz</string> <string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ Giriş edilməyəndə və ya gizli rejimdə uşaq videolarÄą oynadÄąla bilməz</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">İstək ÃŧçÃŧn Statistikada gÃļstər</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">İstək ÃŧçÃŧn Statistikada gÃļstər</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Qəbuledici nÃļvÃŧ İstək ÃŧçÃŧn statistikada gÃļstərilir</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Qəbuledici nÃļvÃŧ İstək ÃŧçÃŧn statistikada gÃļstərilir</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Qəbuledici nerd ÃŧçÃŧn Statistikada gizlidir</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Qəbuledici nerd ÃŧçÃŧn Statistikada gizlidir</string>
<string name="revanced_spoof_video_streams_language_title">VR-da ilkin səs yayımı dili</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>
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
<string name="revanced_settings_music_screen_0_about_title">HaqqÄąnda</string>
<string name="revanced_settings_music_screen_1_ads_title">Reklamlar</string>
<string name="revanced_settings_music_screen_2_general_title">Ümumi</string>
<string name="revanced_settings_music_screen_3_player_title">OynadÄącÄą</string>
<string name="revanced_settings_music_screen_4_misc_title">ÇoxvariantlÄą</string>
</patch>
<patch id="ad.video.hideVideoAdsPatch">
<string name="revanced_music_hide_video_ads_title">Video reklamlarını gizlət</string>
<string name="revanced_music_hide_video_ads_summary_on">Video reklamlarÄą gizlidir</string>
<string name="revanced_music_hide_video_ads_summary_off">Video reklamlarÄą gÃļrÃŧnÃŧr</string>
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
<string name="revanced_music_play_permanent_repeat_title">Kəsintisiz təkrarlamanÄą aktivləşdir</string>
<string name="revanced_music_play_permanent_repeat_summary_on">Kəsintisiz təkrarlama aktivdir</string>
<string name="revanced_music_play_permanent_repeat_summary_off">Kəsintisiz təkrarlama qapalıdır</string>
</patch>
<patch id="layout.compactheader.hideCategoryBar">
<string name="revanced_music_hide_category_bar_title">Kateqoriya cizgisin gizlət</string>
<string name="revanced_music_hide_category_bar_summary_on">Kateqoriya cizgisi gizlidir</string>
<string name="revanced_music_hide_category_bar_summary_off">Kateqoriya cizgisi gÃļrÃŧnÃŧr</string>
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title"> \'Musiqi Premiumu Əldə et\' etiketini gizlət</string>
<string name="revanced_music_hide_get_premium_label_summary_on">Etiket gizlidir</string>
<string name="revanced_music_hide_get_premium_label_summary_off">Etiket gÃļrÃŧnÃŧr</string>
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
<string name="revanced_music_hide_upgrade_button_title">Təkmilləşdirmə dÃŧyməsini gizlət</string>
<string name="revanced_music_hide_upgrade_button_summary_on">DÃŧymə gizlidir</string>
<string name="revanced_music_hide_upgrade_button_summary_off">DÃŧymə gÃļrÃŧnÃŧr</string>
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. --> and changes made here must also be made there. -->
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">НаĐģĐ°Đ´Ņ‹ GmsCore</string>
<string name="microg_settings_summary">НаĐģĐ°Đ´Ņ‹ Đ´ĐģŅ GmsCore</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="gms_core_toast_not_installed_message">MicroG GmsCore ĐŊĐĩ ŅžŅŅ‚Đ°ĐģŅĐ˛Đ°ĐŊŅ‹. ĐŖŅŅ‚Đ°ĐģŅŽĐšŅ†Đĩ ŅĐŗĐž.</string> <string name="gms_core_toast_not_installed_message">MicroG GmsCore ĐŊĐĩ ŅžŅŅ‚Đ°ĐģŅĐ˛Đ°ĐŊŅ‹. ĐŖŅŅ‚Đ°ĐģŅŽĐšŅ†Đĩ ŅĐŗĐž.</string>
<string name="gms_core_dialog_title">ĐŸĐ°Ņ‚Ņ€Đ°ĐąŅƒĐĩŅ†Ņ†Đ° дСĐĩŅĐŊĐŊĐĩ</string> <string name="gms_core_dialog_title">ĐŸĐ°Ņ‚Ņ€Đ°ĐąŅƒĐĩŅ†Ņ†Đ° дСĐĩŅĐŊĐŊĐĩ</string>
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
ĐĐ°Ņ†Ņ–ŅĐŊҖ҆Đĩ ĐēĐŊĐžĐŋĐē҃ \"ĐŸŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ\" Ņ– даСвОĐģŅŒŅ†Đĩ СĐŧŅĐŊŅ–Ņ†ŅŒ аĐŋ҂ҋĐŧŅ–ĐˇĐ°Ņ†Ņ‹ŅŽ."</string> ĐĐ°Ņ†Ņ–ŅĐŊҖ҆Đĩ ĐēĐŊĐžĐŋĐē҃ \"ĐŸŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ\" Ņ– даСвОĐģŅŒŅ†Đĩ СĐŧŅĐŊŅ–Ņ†ŅŒ аĐŋ҂ҋĐŧŅ–ĐˇĐ°Ņ†Ņ‹ŅŽ."</string>
<string name="gms_core_dialog_continue_text">ĐŸŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ</string> <string name="gms_core_dialog_continue_text">ĐŸŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">ПоддĐĩĐģŅ‹Đ˛Đ°Ņ‚ŅŒ ĐŋĐžŅ‚ĐžĐēи видĐĩĐž</string>
<string name="revanced_spoof_video_streams_screen_summary">ИĐŧĐ¸Ņ‚Đ¸Ņ€ŅƒĐšŅ‚Đĩ ĐŋĐžŅ‚ĐžĐēи видĐĩĐž ĐēĐģиĐĩĐŊŅ‚ĐžĐ˛, Ņ‡Ņ‚ĐžĐąŅ‹ ĐŋŅ€ĐĩĐ´ĐžŅ‚Đ˛Ņ€Đ°Ņ‚Đ¸Ņ‚ŅŒ ĐŋŅ€ĐžĐąĐģĐĩĐŧŅ‹ ҁ Đ˛ĐžŅĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐ´ĐĩĐŊиĐĩĐŧ</string>
<string name="revanced_spoof_video_streams_screen_title">ПадĐŧĐĩĐŊа Đ˛Ņ–Đ´ŅĐ°ĐŋĐ°Ņ‚ĐžĐēĐ°Ņž</string>
<string name="revanced_spoof_video_streams_screen_summary">ПадĐŧĐĩĐŊа Đ˛Ņ–Đ´ŅĐ°ĐŋĐ°Ņ‚ĐžĐēĐ°Ņž ĐēĐģŅ–ĐĩĐŊŅ‚Đ° Đ´ĐģŅ ĐŋŅ€Đ°Đ´ŅƒŅ…Ņ–ĐģĐĩĐŊĐŊŅ ĐŋŅ€Đ°ĐąĐģĐĩĐŧ С ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩĐŧ</string>
<string name="revanced_spoof_video_streams_title">ПоддĐĩĐģŅ‹Đ˛Đ°Ņ‚ŅŒ ĐŋĐžŅ‚ĐžĐēи видĐĩĐž</string>
<string name="revanced_spoof_video_streams_summary_on">"Đ’Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅ– ĐŋĐ°Đ´Ņ€ĐžĐąĐģĐĩĐŊŅ‹
КаĐģŅ– Đ˛Ņ‹ ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°Đĩ҆ĐĩŅŅ YouTube Premium, ĐŗŅŅ‚Đ°Ņ ĐŊаĐģада ĐŧĐžĐļа ĐŊĐĩ ҁĐŋĐ°Ņ‚Ņ€ŅĐąŅ–Ņ†Ņ†Đ°"</string>
<string name="revanced_spoof_video_streams_summary_off">"Đ’Ņ–Đ´ŅĐ°ĐŋĐ°Ņ‚ĐžĐēŅ– ĐŊĐĩ ĐŋадĐŧĐĩĐŊĐĩĐŊŅ‹
ĐŸŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩ ĐŧĐžĐļа ĐŊĐĩ ĐŋŅ€Đ°Ņ†Đ°Đ˛Đ°Ņ†ŅŒ"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">АдĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°Đš ĐŊаĐģĐ°Đ´Ņ‹ ĐŧĐžĐļа Đ˛Ņ‹ĐēĐģŅ–ĐēĐ°Ņ†ŅŒ ĐŋŅ€Đ°ĐąĐģĐĩĐŧŅ‹ С ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩĐŧ.</string>
<string name="revanced_spoof_video_streams_client_type_title">КĐģиĐĩĐŊŅ‚ ĐŋĐž ҃ĐŧĐžĐģŅ‡Đ°ĐŊĐ¸ŅŽ</string>
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">АдĐģадĐēа</string>
<string name="revanced_debug_screen_summary">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ айО Đ˛Ņ‹ĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŋĐ°Ņ€Đ°ĐŧĐĩ҂Ҁҋ адĐģадĐēŅ–</string>
<string name="revanced_debug_title">ЗаĐŋҖҁ адĐģадĐēŅ–</string>
<string name="revanced_debug_summary_on">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ŅžĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_debug_summary_off">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– адĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_debug_export_logs_to_clipboard_title">Đ­ĐēҁĐŋĐ°Ņ€Ņ‚Đ°Đ˛Đ°Ņ†ŅŒ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ–</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">КаĐŋŅ–Ņ€ŅƒĐĩ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ– ReVanced ҃ ĐąŅƒŅ„ĐĩŅ€ айĐŧĐĩĐŊ҃</string>
<string name="revanced_debug_logs_disabled">АдĐģĐ°Đ´Đ°Ņ‡ĐŊаĐĩ ĐģĐ°ĐŗĐ°Đ˛Đ°ĐŊĐŊĐĩ адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_debug_logs_none_found">Đ›Đ°ĐŗŅ– ĐŊĐĩ СĐŊОКдСĐĩĐŊŅ‹</string>
<string name="revanced_debug_logs_copied_to_clipboard">Đ›Đ°ĐŗŅ– ҁĐēаĐŋŅ–ŅĐ˛Đ°ĐŊŅ‹</string>
<string name="revanced_debug_logs_failed_to_export">НĐĩ ŅžĐ´Đ°ĐģĐžŅŅ ŅĐēҁĐŋĐ°Ņ€Ņ‚Đ°Đ˛Đ°Ņ†ŅŒ ĐļŅƒŅ€ĐŊаĐģŅ‹: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">ĐŅ‡Ņ‹ŅŅ†Ņ–Ņ†ŅŒ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ–</string>
<string name="revanced_debug_logs_clear_buffer_summary">ĐŅ‡Ņ‹ŅˆŅ‡Đ°Đĩ ŅžŅĐĩ ĐˇĐ°Ņ…Đ°Đ˛Đ°ĐŊŅ‹Ņ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ– ReVanced</string>
<string name="revanced_debug_logs_clear_toast">Đ›Đ°ĐŗŅ– Đ°Ņ‡Ņ‹ŅˆŅ‡Đ°ĐŊŅ‹</string>
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊĐžĐ˛Ņ‹Đš ĐŋĐģĐĩĐšĐģĐ¸ŅŅ‚ Shorts вĐēĐģŅŽŅ‡ĐĩĐŊ</string> <string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊĐžĐ˛Ņ‹Đš ĐŋĐģĐĩĐšĐģĐ¸ŅŅ‚ Shorts вĐēĐģŅŽŅ‡ĐĩĐŊ</string>
</patch> </patch>
<patch id="misc.debugging.enableDebuggingPatch"> <patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">АдĐģадĐēа</string>
<string name="revanced_debug_screen_summary">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ айО Đ˛Ņ‹ĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŋĐ°Ņ€Đ°ĐŧĐĩ҂Ҁҋ адĐģадĐēŅ–</string>
<string name="revanced_debug_title">ЗаĐŋҖҁ адĐģадĐēŅ–</string>
<string name="revanced_debug_summary_on">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ŅžĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_debug_summary_off">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– адĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_debug_protobuffer_title">Đ‘ŅƒŅ„ĐĩŅ€ ĐŋŅ€Đ°Ņ‚Đ°ĐēĐžĐģ҃ Ņ‡Đ°ŅĐžĐŋŅ–ŅĐ°</string> <string name="revanced_debug_protobuffer_title">Đ‘ŅƒŅ„ĐĩŅ€ ĐŋŅ€Đ°Ņ‚Đ°ĐēĐžĐģ҃ Ņ‡Đ°ŅĐžĐŋŅ–ŅĐ°</string>
<string name="revanced_debug_protobuffer_summary_on">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ŅžĐēĐģŅŽŅ‡Đ°ŅŽŅ†ŅŒ ĐŋŅ€Đ°Ņ‚Đ°ĐąŅƒŅ„ĐĩŅ€</string> <string name="revanced_debug_protobuffer_summary_on">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ŅžĐēĐģŅŽŅ‡Đ°ŅŽŅ†ŅŒ ĐŋŅ€Đ°Ņ‚Đ°ĐąŅƒŅ„ĐĩŅ€</string>
<string name="revanced_debug_protobuffer_summary_off">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ĐŊĐĩ ŅžĐēĐģŅŽŅ‡Đ°ŅŽŅ†ŅŒ ĐŋŅ€Đ°Ņ‚Đ°ĐąŅƒŅ„ĐĩŅ€</string> <string name="revanced_debug_protobuffer_summary_off">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ĐŊĐĩ ŅžĐēĐģŅŽŅ‡Đ°ŅŽŅ†ŅŒ ĐŋŅ€Đ°Ņ‚Đ°ĐąŅƒŅ„ĐĩŅ€</string>
@@ -132,15 +160,6 @@ Second \"item\" text"</string>
<string name="revanced_debug_toast_on_error_user_dialog_message">"АдĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŋавĐĩдаĐŧĐģĐĩĐŊĐŊŅŅž ĐŋŅ€Đ° ĐŋаĐŧŅ‹ĐģĐēŅ– ŅŅ…Đ°Đ˛Đ°Đĩ ŅžŅĐĩ аĐŋĐ°Đ˛ŅŅˆŅ‡ŅĐŊĐŊŅ– ReVanced ĐŋŅ€Đ° ĐŋаĐŧŅ‹ĐģĐēŅ–. <string name="revanced_debug_toast_on_error_user_dialog_message">"АдĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŋавĐĩдаĐŧĐģĐĩĐŊĐŊŅŅž ĐŋŅ€Đ° ĐŋаĐŧŅ‹ĐģĐēŅ– ŅŅ…Đ°Đ˛Đ°Đĩ ŅžŅĐĩ аĐŋĐ°Đ˛ŅŅˆŅ‡ŅĐŊĐŊŅ– ReVanced ĐŋŅ€Đ° ĐŋаĐŧŅ‹ĐģĐēŅ–.
Đ’Ņ‹ ĐŊĐĩ ĐąŅƒĐ´ĐˇĐĩ҆Đĩ Đ°Ņ‚Ņ€Ņ‹ĐŧĐģŅ–Đ˛Đ°Ņ†ŅŒ аĐŋĐ°Đ˛ŅŅˆŅ‡ŅĐŊĐŊŅ– ĐŋŅ€Đ° ĐŊĐĩŅ‡Đ°ĐēаĐŊŅ‹Ņ ĐŋадСĐĩŅ–."</string> Đ’Ņ‹ ĐŊĐĩ ĐąŅƒĐ´ĐˇĐĩ҆Đĩ Đ°Ņ‚Ņ€Ņ‹ĐŧĐģŅ–Đ˛Đ°Ņ†ŅŒ аĐŋĐ°Đ˛ŅŅˆŅ‡ŅĐŊĐŊŅ– ĐŋŅ€Đ° ĐŊĐĩŅ‡Đ°ĐēаĐŊŅ‹Ņ ĐŋадСĐĩŅ–."</string>
<string name="revanced_debug_export_logs_to_clipboard_title">Đ­ĐēҁĐŋĐ°Ņ€Ņ‚Đ°Đ˛Đ°Ņ†ŅŒ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ–</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">КаĐŋŅ–Ņ€ŅƒĐĩ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ– ReVanced ҃ ĐąŅƒŅ„ĐĩŅ€ айĐŧĐĩĐŊ҃</string>
<string name="revanced_debug_logs_disabled">АдĐģĐ°Đ´Đ°Ņ‡ĐŊаĐĩ ĐģĐ°ĐŗĐ°Đ˛Đ°ĐŊĐŊĐĩ адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_debug_logs_none_found">Đ›Đ°ĐŗŅ– ĐŊĐĩ СĐŊОКдСĐĩĐŊŅ‹</string>
<string name="revanced_debug_logs_copied_to_clipboard">Đ›Đ°ĐŗŅ– ҁĐēаĐŋŅ–ŅĐ˛Đ°ĐŊŅ‹</string>
<string name="revanced_debug_logs_failed_to_export">НĐĩ ŅžĐ´Đ°ĐģĐžŅŅ ŅĐēҁĐŋĐ°Ņ€Ņ‚Đ°Đ˛Đ°Ņ†ŅŒ ĐļŅƒŅ€ĐŊаĐģŅ‹: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">ĐŅ‡Ņ‹ŅŅ†Ņ–Ņ†ŅŒ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ–</string>
<string name="revanced_debug_logs_clear_buffer_summary">ĐŅ‡Ņ‹ŅˆŅ‡Đ°Đĩ ŅžŅĐĩ ĐˇĐ°Ņ…Đ°Đ˛Đ°ĐŊŅ‹Ņ адĐģĐ°Đ´Đ°Ņ‡ĐŊŅ‹Ņ ĐģĐ°ĐŗŅ– ReVanced</string>
<string name="revanced_debug_logs_clear_toast">Đ›Đ°ĐŗŅ– Đ°Ņ‡Ņ‹ŅˆŅ‡Đ°ĐŊŅ‹</string>
</patch> </patch>
<patch id="layout.hide.general.hideLayoutComponentsPatch"> <patch id="layout.hide.general.hideLayoutComponentsPatch">
<string name="revanced_hide_album_cards_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐ°Ņ€Ņ‚Ņ‹ аĐģŅŒĐąĐžĐŧа</string> <string name="revanced_hide_album_cards_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐ°Ņ€Ņ‚Ņ‹ аĐģŅŒĐąĐžĐŧа</string>
@@ -602,6 +621,10 @@ Second \"item\" text"</string>
<string name="revanced_hide_clip_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐģŅ–Đŋ</string> <string name="revanced_hide_clip_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐģŅ–Đŋ</string>
<string name="revanced_hide_clip_button_summary_on">КĐŊĐžĐŋĐēа ĐēĐģŅ–Đŋа ŅŅ…Đ°Đ˛Đ°ĐŊа</string> <string name="revanced_hide_clip_button_summary_on">КĐŊĐžĐŋĐēа ĐēĐģŅ–Đŋа ŅŅ…Đ°Đ˛Đ°ĐŊа</string>
<string name="revanced_hide_clip_button_summary_off">ПаĐēаСаĐŊа ĐēĐŊĐžĐŋĐēа ĐēĐģŅ–Đŋа</string> <string name="revanced_hide_clip_button_summary_off">ПаĐēаСаĐŊа ĐēĐŊĐžĐŋĐēа ĐēĐģŅ–Đŋа</string>
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_shop_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐšŅ€Đ°Đŧ҃</string>
<string name="revanced_hide_shop_button_summary_on">КĐŊĐžĐŋĐēа \"ĐšŅ€Đ°Đŧа\" ŅŅ…Đ°Đ˛Đ°ĐŊа</string>
<string name="revanced_hide_shop_button_summary_off">КĐŊĐžĐŋĐēа \"ĐšŅ€Đ°Đŧа\" ĐŋаĐēаСаĐŊа</string>
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_save_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ \"Đ—Đ°Ņ…Đ°Đ˛Đ°Ņ†ŅŒ\"</string> <string name="revanced_hide_save_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ \"Đ—Đ°Ņ…Đ°Đ˛Đ°Ņ†ŅŒ\"</string>
<string name="revanced_hide_save_button_summary_on">КĐŊĐžĐŋĐēа \"Đ—Đ°Ņ…Đ°Đ˛Đ°Ņ†ŅŒ\" ŅŅ…Đ°Đ˛Đ°ĐŊа</string> <string name="revanced_hide_save_button_summary_on">КĐŊĐžĐŋĐēа \"Đ—Đ°Ņ…Đ°Đ˛Đ°Ņ†ŅŒ\" ŅŅ…Đ°Đ˛Đ°ĐŊа</string>
@@ -702,7 +725,7 @@ Second \"item\" text"</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_hide_player_flyout_audio_track_not_available">"МĐĩĐŊŅŽ Đ°ŅžĐ´Ņ‹ŅĐ´Đ°Ņ€ĐžĐļĐēŅ– ŅŅ…Đ°Đ˛Đ°ĐŊа <string name="revanced_hide_player_flyout_audio_track_not_available">"МĐĩĐŊŅŽ Đ°ŅžĐ´Ņ‹ŅĐ´Đ°Ņ€ĐžĐļĐēŅ– ŅŅ…Đ°Đ˛Đ°ĐŊа
Каб ĐŋаĐēĐ°ĐˇĐ°Ņ†ŅŒ ĐŧĐĩĐŊŅŽ Đ°ŅžĐ´Ņ‹ŅĐ´Đ°Ņ€ĐžĐļĐēŅ–, СĐŧŅĐŊҖ҆Đĩ \"ĐŸĐ°Đ´Ņ€ĐžĐąĐēа Đ˛Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅŅž\" ĐŊа iOS TV"</string> Каб ĐŋаĐēĐ°ĐˇĐ°Ņ†ŅŒ ĐŧĐĩĐŊŅŽ Đ°ŅžĐ´Ņ‹ŅĐ´Đ°Ņ€ĐžĐļĐēŅ–, СĐŧŅĐŊҖ҆Đĩ \"ПадĐŧĐĩĐŊа Đ˛Ņ–Đ´ŅĐ°ĐŋĐ°Ņ‚ĐžĐēĐ°Ņž\" ĐŊа iPadOS"</string>
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. --> <!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐŗĐ°Đ´ĐˇŅ–ĐŊĐŊŅ–Đē ҃ VR</string> <string name="revanced_hide_player_flyout_watch_in_vr_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐŗĐ°Đ´ĐˇŅ–ĐŊĐŊŅ–Đē ҃ VR</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">МĐĩĐŊŅŽ ĐŋŅ€Đ°ĐŗĐģŅĐ´Ņƒ Ņž VR ŅŅ…Đ°Đ˛Đ°ĐŊа</string> <string name="revanced_hide_player_flyout_watch_in_vr_summary_on">МĐĩĐŊŅŽ ĐŋŅ€Đ°ĐŗĐģŅĐ´Ņƒ Ņž VR ŅŅ…Đ°Đ˛Đ°ĐŊа</string>
@@ -1416,10 +1439,6 @@ Second \"item\" text"</string>
ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа Ņ€Đ°ĐˇĐąĐģаĐēĐ°Đ˛Đ°Ņ†ŅŒ йОĐģҌ҈ Đ˛Ņ‹ŅĐžĐēŅ–Ņ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°"</string> ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа Ņ€Đ°ĐˇĐąĐģаĐēĐ°Đ˛Đ°Ņ†ŅŒ йОĐģҌ҈ Đ˛Ņ‹ŅĐžĐēŅ–Ņ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа ĐŋŅ€Ņ‹Đ˛Đĩҁ҆Җ да ĐŋҀҋĐŋŅ‹ĐŊĐēĐ°Ņž ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊŅ Đ˛Ņ–Đ´ŅĐ°, ĐŋĐ°ĐŗĐ°Ņ€ŅˆŅĐŊĐŊŅ Ņ‚ŅŅ€ĐŧŅ–ĐŊ҃ ҁĐģ҃ĐļĐąŅ‹ ĐąĐ°Ņ‚Đ°Ņ€ŅŅ– Ņ– ĐŊĐĩĐ˛ŅĐ´ĐžĐŧҋ҅ ĐŋĐ°ĐąĐžŅ‡ĐŊҋ҅ ŅŅ„ĐĩĐēŅ‚Đ°Ņž.</string> <string name="revanced_spoof_device_dimensions_user_dialog_message">ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа ĐŋŅ€Ņ‹Đ˛Đĩҁ҆Җ да ĐŋҀҋĐŋŅ‹ĐŊĐēĐ°Ņž ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊŅ Đ˛Ņ–Đ´ŅĐ°, ĐŋĐ°ĐŗĐ°Ņ€ŅˆŅĐŊĐŊŅ Ņ‚ŅŅ€ĐŧŅ–ĐŊ҃ ҁĐģ҃ĐļĐąŅ‹ ĐąĐ°Ņ‚Đ°Ņ€ŅŅ– Ņ– ĐŊĐĩĐ˛ŅĐ´ĐžĐŧҋ҅ ĐŋĐ°ĐąĐžŅ‡ĐŊҋ҅ ŅŅ„ĐĩĐēŅ‚Đ°Ņž.</string>
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">НаĐģĐ°Đ´Ņ‹ GmsCore</string>
<string name="microg_settings_summary">НаĐģĐ°Đ´Ņ‹ Đ´ĐģŅ GmsCore</string>
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
<string name="revanced_disable_haptic_feedback_title">ĐĸаĐē҂ҋĐģҌĐŊĐ°Ņ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊĐ°Ņ ŅŅƒĐ˛ŅĐˇŅŒ</string> <string name="revanced_disable_haptic_feedback_title">ĐĸаĐē҂ҋĐģҌĐŊĐ°Ņ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊĐ°Ņ ŅŅƒĐ˛ŅĐˇŅŒ</string>
<string name="revanced_disable_haptic_feedback_summary">ЗĐŧŅĐŊŅ–Ņ†ŅŒ Ņ‚Đ°Đē҂ҋĐģҌĐŊŅƒŅŽ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊŅƒŅŽ ŅŅƒĐ˛ŅĐˇŅŒ</string> <string name="revanced_disable_haptic_feedback_summary">ЗĐŧŅĐŊŅ–Ņ†ŅŒ Ņ‚Đ°Đē҂ҋĐģҌĐŊŅƒŅŽ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊŅƒŅŽ ŅŅƒĐ˛ŅĐˇŅŒ</string>
@@ -1459,7 +1478,7 @@ Second \"item\" text"</string>
<string name="revanced_force_original_audio_summary_on">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Ņ†ŅŒ Đ°Ņ€Ņ‹ĐŗŅ–ĐŊаĐģҌĐŊŅƒŅŽ ĐŧĐžĐ˛Ņƒ Đ°ŅžĐ´Ņ‹Ņ</string> <string name="revanced_force_original_audio_summary_on">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Ņ†ŅŒ Đ°Ņ€Ņ‹ĐŗŅ–ĐŊаĐģҌĐŊŅƒŅŽ ĐŧĐžĐ˛Ņƒ Đ°ŅžĐ´Ņ‹Ņ</string>
<string name="revanced_force_original_audio_summary_off">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐŊĐŊĐĩ Đ°ŅžĐ´Ņ‹Ņ‘ Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ–</string> <string name="revanced_force_original_audio_summary_off">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐŊĐŊĐĩ Đ°ŅžĐ´Ņ‹Ņ‘ Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ–</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">Каб Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Ņ†ŅŒ ĐŗŅŅ‚Ņƒ Ņ„ŅƒĐŊĐēŅ†Ņ‹ŅŽ, СĐŧŅĐŊҖ҆Đĩ ĐŋĐ°Ņ€Đ°ĐŧĐĩ҂Ҁ \"ĐŸĐ°Đ´Ņ€Đ°ĐąĐģŅŅ†ŅŒ Đ˛Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅ–\" ĐŊа iOS TV</string> <string name="revanced_force_original_audio_not_available">Каб Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°Ņ†ŅŒ ĐŗŅŅ‚ŅƒŅŽ Ņ„ŅƒĐŊĐēŅ†Ņ‹ŅŽ, СĐŧŅĐŊҖ҆Đĩ \'ПадĐŧĐĩĐŊа Đ˛Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅŅž\' ĐŊа ĐģŅŽĐąĐžĐŗĐ° ĐēĐģŅ–ĐĩĐŊŅ‚Đ°, аĐēŅ€Đ°ĐŧŅ Android Studio</string>
</patch> </patch>
<patch id="video.quality.rememberVideoQualityPatch"> <patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. --> <!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1533,35 +1552,54 @@ Second \"item\" text"</string>
<string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃ ĐŊĐĩ ŅžĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string> <string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃ ĐŊĐĩ ŅžĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">ПоддĐĩĐģŅ‹Đ˛Đ°Ņ‚ŅŒ ĐŋĐžŅ‚ĐžĐēи видĐĩĐž</string> <string name="revanced_spoof_video_streams_about_title">ĐŸĐ°ĐąĐžŅ‡ĐŊŅ‹Ņ ŅŅ„ĐĩĐē҂ҋ ĐŋĐ°Đ´Ņ€ĐžĐąĐēŅ–</string>
<string name="revanced_spoof_video_streams_screen_summary">ИĐŧĐ¸Ņ‚Đ¸Ņ€ŅƒĐšŅ‚Đĩ ĐŋĐžŅ‚ĐžĐēи видĐĩĐž ĐēĐģиĐĩĐŊŅ‚ĐžĐ˛, Ņ‡Ņ‚ĐžĐąŅ‹ ĐŋŅ€ĐĩĐ´ĐžŅ‚Đ˛Ņ€Đ°Ņ‚Đ¸Ņ‚ŅŒ ĐŋŅ€ĐžĐąĐģĐĩĐŧŅ‹ ҁ Đ˛ĐžŅĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐ´ĐĩĐŊиĐĩĐŧ</string>
<string name="revanced_spoof_video_streams_title">ПоддĐĩĐģŅ‹Đ˛Đ°Ņ‚ŅŒ ĐŋĐžŅ‚ĐžĐēи видĐĩĐž</string>
<string name="revanced_spoof_video_streams_summary_on">ĐŸĐžŅ‚ĐžĐēи видĐĩĐž ĐŋОддĐĩĐģаĐŊŅ‹</string>
<string name="revanced_spoof_video_streams_summary_off">"Đ’Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧ ĐŊĐĩ ĐŋĐ°Đ´Ņ€ĐžĐąĐģĐĩĐŊŅ‹
ĐŸŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐļа ĐŊĐĩ ĐŋŅ€Đ°Ņ†Đ°Đ˛Đ°Ņ†ŅŒ"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">АдĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°Đš ĐŊаĐģĐ°Đ´Ņ‹ ĐŧĐžĐļа Đ˛Ņ‹ĐēĐģŅ–ĐēĐ°Ņ†ŅŒ ĐŋŅ€Đ°ĐąĐģĐĩĐŧŅ‹ С ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩĐŧ Đ˛Ņ–Đ´ŅĐ°.</string>
<string name="revanced_spoof_video_streams_client_type_title">КĐģиĐĩĐŊŅ‚ ĐŋĐž ҃ĐŧĐžĐģŅ‡Đ°ĐŊĐ¸ŅŽ</string>
<string name="revanced_spoof_video_streams_ios_force_avc_title">Đ’Ņ‹ĐŧŅƒŅŅ–Ņ†ŅŒ iOS AVC (H.264)</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">Đ’Ņ–Đ´ŅĐ°ĐēaĐ´ŅĐē ĐˇĐ°Ņ„Ņ–ĐēŅĐ°Đ˛Đ°ĐŊŅ‹ Ņž AVC (H.264)</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">Đ’Ņ–Đ´ŅĐ°ĐēaĐ´ŅĐē Đ˛Ņ‹ĐˇĐŊĐ°Ņ‡Đ°ĐĩŅ†Ņ†Đ° Đ°ŅžŅ‚Đ°ĐŧĐ°Ņ‚Ņ‹Ņ‡ĐŊа</string>
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа ĐŋаĐģĐĩĐŋŅˆŅ‹Ņ†ŅŒ Ņ‡Đ°Ņ Đ°ŅžŅ‚Đ°ĐŊĐžĐŧĐŊаК ĐŋŅ€Đ°Ņ†Ņ‹ Ņ– Đ˛Ņ‹ĐŋŅ€Đ°Đ˛Ņ–Ņ†ŅŒ ĐˇĐ°Ņ–ĐēаĐŊĐŊĐĩ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊŅ.
AVC ĐŧаĐĩ ĐŧаĐēҁҖĐŧаĐģҌĐŊаĐĩ даСвОĐģ 1080p, Đ°ŅžĐ´Ņ‹Ņ‘ĐēĐ°Đ´ŅĐē Opus ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹, а ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩ Đ˛Ņ–Đ´ŅĐ° ĐąŅƒĐ´ĐˇĐĩ Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Ņ†ŅŒ йОĐģҌ҈ Ņ–ĐŊŅ‚ŅŅ€ĐŊŅŅ‚-даĐŊҋ҅, ҇ҋĐŧ VP9 айО AV1."</string>
<string name="revanced_spoof_video_streams_about_ios_tv_title">ĐŸĐ°ĐąĐžŅ‡ĐŊŅ‹Ņ ŅŅ„ĐĩĐē҂ҋ ĐŋĐ°Đ´Ņ€ĐžĐąĐēŅ– iOS</string>
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"â€ĸ Đ¤Ņ–ĐģҌĐŧŅ‹ айО ĐŋĐģĐ°Ņ‚ĐŊŅ‹Ņ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐŗŅƒŅ†ŅŒ ĐŊĐĩ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°Ņ†Ņ†Đ°
â€ĸ ĐĄŅ‚Đ°ĐąŅ–ĐģҌĐŊĐ°Ņ ĐŗŅƒŅ‡ĐŊĐ°ŅŅ†ŅŒ ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊĐ°Ņ
â€ĸ Đ’Ņ–Đ´ŅĐ° СаĐēаĐŊŅ‡Đ˛Đ°ŅŽŅ†Ņ†Đ° ĐŊа 1 ҁĐĩĐē҃ĐŊĐ´Ņƒ Ņ€Đ°ĐŊĐĩĐš"</string>
<string name="revanced_spoof_video_streams_about_android_title">ĐŸĐžĐąŅ–Ņ‡ĐŊŅ‹Ņ ŅŅ„ĐĩĐē҂ҋ ĐŋĐ°Đ´Ņ€ĐžĐąĐēŅ– Android</string> <string name="revanced_spoof_video_streams_about_android_title">ĐŸĐžĐąŅ–Ņ‡ĐŊŅ‹Ņ ŅŅ„ĐĩĐē҂ҋ ĐŋĐ°Đ´Ņ€ĐžĐąĐēŅ– Android</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ МĐĩĐŊŅŽ ĐŗŅƒĐēавОК Đ´Đ°Ņ€ĐžĐļĐēŅ– Đ°Đ´ŅŅƒŅ‚ĐŊŅ–Ņ‡Đ°Đĩ <string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ МĐĩĐŊŅŽ ĐŗŅƒĐēавОК Đ´Đ°Ņ€ĐžĐļĐēŅ– Đ°Đ´ŅŅƒŅ‚ĐŊŅ–Ņ‡Đ°Đĩ
â€ĸ ĐĄŅ‚Đ°ĐąŅ–ĐģҌĐŊŅ‹ ĐŗŅƒĐē ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹ â€ĸ ĐĄŅ‚Đ°ĐąŅ–ĐģҌĐŊĐ°Ņ ĐŗŅƒŅ‡ĐŊĐ°ŅŅ†ŅŒ ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊа"</string>
â€ĸ ĐŸŅ€Ņ‹ĐŧŅƒŅĐžĐ˛Đ°Đĩ Đ°Ņ€Ņ‹ĐŗŅ–ĐŊаĐģҌĐŊаĐĩ Đ°ŅžĐ´Ņ‹Ņ‘ ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊа"</string> <string name="revanced_spoof_video_streams_about_ipados_summary">â€ĸ Đ’Ņ–Đ´ŅĐ° ĐŧĐžĐļа ҁĐŋŅ‹ĐŊŅ–Ņ†Ņ†Đ° ĐŊа 1:00, ҆Җ ĐŧĐžĐļа ĐąŅ‹Ņ†ŅŒ ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹Đŧ ҃ ĐŊĐĩĐēĐ°Ņ‚ĐžŅ€Ņ‹Ņ… Ņ€ŅĐŗŅ–Ņ‘ĐŊĐ°Ņ…</string>
<string name="revanced_spoof_video_streams_about_experimental">â€ĸ Đ­ĐēҁĐŋĐĩҀҋĐŧĐĩĐŊŅ‚Đ°ĐģҌĐŊŅ‹ ĐēĐģŅ–ĐĩĐŊŅ‚ Ņ– ĐŧĐžĐļа ҁĐŋŅ‹ĐŊŅ–Ņ†ŅŒ ĐŋŅ€Đ°Ņ†Ņƒ Ņž ĐģŅŽĐąŅ‹ Ņ‡Đ°Ņ</string>
<string name="revanced_spoof_video_streams_about_no_av1">â€ĸ ĐŅĐŧа Đ˛Ņ–Đ´ŅĐ°ĐēŅ–Đ´Đ°Đ˛Đ°ĐŊĐŊŅ AV1</string> <string name="revanced_spoof_video_streams_about_no_av1">â€ĸ ĐŅĐŧа Đ˛Ņ–Đ´ŅĐ°ĐēŅ–Đ´Đ°Đ˛Đ°ĐŊĐŊŅ AV1</string>
<string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ Đ”ĐˇŅ–Ņ†ŅŅ‡Ņ‹Ņ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐŗŅƒŅ†ŅŒ ĐŊĐĩ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°Ņ†Ņ†Đ° Ņž ŅŅ‚Đ°ĐŊĐĩ Đ˛Ņ‹Ņ…Đ°Đ´Ņƒ С аĐēĐ°ŅžĐŊŅ‚Đ° айО Ņž Ņ€ŅĐļŅ‹ĐŧĐĩ Ņ–ĐŊĐēĐžĐŗĐŊŅ–Ņ‚Đ°</string> <string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ Đ”ĐˇŅ–Ņ†ŅŅ‡Ņ‹Ņ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐŗŅƒŅ†ŅŒ ĐŊĐĩ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°Ņ†Ņ†Đ° Ņž ŅŅ‚Đ°ĐŊĐĩ Đ˛Ņ‹Ņ…Đ°Đ´Ņƒ С аĐēĐ°ŅžĐŊŅ‚Đ° айО Ņž Ņ€ŅĐļŅ‹ĐŧĐĩ Ņ–ĐŊĐēĐžĐŗĐŊŅ–Ņ‚Đ°</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">ПаĐēĐ°ĐˇĐ°Ņ†ŅŒ ҃ ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">ПаĐēĐ°ĐˇĐ°Ņ†ŅŒ ҃ ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">ĐĸŅ‹Đŋ ĐēĐģŅ–ĐĩĐŊŅ‚Đ° адĐģŅŽŅŅ‚Ņ€ĐžŅžĐ˛Đ°ĐĩŅ†Ņ†Đ° Ņž ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">ĐĸŅ‹Đŋ ĐēĐģŅ–ĐĩĐŊŅ‚Đ° адĐģŅŽŅŅ‚Ņ€ĐžŅžĐ˛Đ°ĐĩŅ†Ņ†Đ° Ņž ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">КĐģŅ–ĐĩĐŊŅ‚ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹ Ņž ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">КĐģŅ–ĐĩĐŊŅ‚ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹ Ņž ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string>
<string name="revanced_spoof_video_streams_language_title">Мова ĐŗŅƒĐēавОК Đ´Đ°Ņ€ĐžĐļĐēŅ– Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ– Đ´ĐģŅ VR</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>
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
<string name="revanced_settings_music_screen_0_about_title">ĐŸŅ€Đ°</string>
<string name="revanced_settings_music_screen_1_ads_title">Đ ŅĐēĐģаĐŧа</string>
<string name="revanced_settings_music_screen_2_general_title">ĐĐŗŅƒĐģҌĐŊŅ‹Ņ</string>
<string name="revanced_settings_music_screen_3_player_title">ПĐģŅĐĩŅ€</string>
<string name="revanced_settings_music_screen_4_misc_title">РОСĐŊаĐĩ</string>
</patch>
<patch id="ad.video.hideVideoAdsPatch">
<string name="revanced_music_hide_video_ads_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ Đ˛Ņ–Đ´ŅĐ°Ņ€ŅĐēĐģаĐŧ҃</string>
<string name="revanced_music_hide_video_ads_summary_on">Đ’Ņ–Đ´ŅĐ°Ņ€ŅĐēĐģаĐŧа ŅŅ…Đ°Đ˛Đ°ĐŊĐ°Ņ</string>
<string name="revanced_music_hide_video_ads_summary_off">Đ’Ņ–Đ´ŅĐ°Ņ€ŅĐēĐģаĐŧа ĐŋаĐēаСаĐŊĐ°Ņ</string>
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
<string name="revanced_music_play_permanent_repeat_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŋĐ°ŅŅ‚Đ°ŅĐŊĐŊŅ‹ ĐŋĐ°ŅžŅ‚ĐžŅ€</string>
<string name="revanced_music_play_permanent_repeat_summary_on">ĐŸĐ°ŅŅ‚Đ°ŅĐŊĐŊŅ‹ ĐŋĐ°ŅžŅ‚ĐžŅ€ ҃ĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_music_play_permanent_repeat_summary_off">ĐŸĐ°ŅŅ‚Đ°ŅĐŊĐŊŅ‹ ĐŋĐ°ŅžŅ‚ĐžŅ€ адĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
</patch>
<patch id="layout.compactheader.hideCategoryBar">
<string name="revanced_music_hide_category_bar_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐŋаĐŊŅĐģҌ ĐēĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹Đš</string>
<string name="revanced_music_hide_category_bar_summary_on">ПаĐŊŅĐģҌ ĐēĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹Đš ŅŅ…Đ°Đ˛Đ°ĐŊĐ°Ņ</string>
<string name="revanced_music_hide_category_bar_summary_off">ПаĐŊŅĐģҌ ĐēĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹Đš ĐŋаĐēаСаĐŊĐ°Ņ</string>
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐŊадĐŋҖҁ \"ĐŅ‚Ņ€Ņ‹ĐŧĐ°Ņ†ŅŒ Music Premium\"</string>
<string name="revanced_music_hide_get_premium_label_summary_on">НадĐŋҖҁ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_music_hide_get_premium_label_summary_off">НадĐŋҖҁ ĐŋаĐēаСаĐŊŅ‹</string>
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
<string name="revanced_music_hide_upgrade_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐŊĐžĐŋĐē҃ айĐŊĐ°ŅžĐģĐĩĐŊĐŊŅ</string>
<string name="revanced_music_hide_upgrade_button_summary_on">КĐŊĐžĐŋĐēа ŅŅ…Đ°Đ˛Đ°ĐŊĐ°Ņ</string>
<string name="revanced_music_hide_upgrade_button_summary_off">КĐŊĐžĐŋĐēа ĐŋаĐēаСаĐŊĐ°Ņ</string>
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. --> and changes made here must also be made there. -->
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore ĐĐ°ŅŅ‚Ņ€ĐžĐšĐēи</string>
<string name="microg_settings_summary">ĐĐ°ŅŅ‚Ņ€ĐžĐšĐēи ĐŊа GmsCore</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="gms_core_toast_not_installed_message">GmsCore ĐŊĐĩ Đĩ иĐŊŅŅ‚Đ°ĐģĐ¸Ņ€Đ°ĐŊ. ИĐŊŅŅ‚Đ°ĐģĐ¸Ņ€Đ°ĐšŅ‚Đĩ ĐŗĐž.</string> <string name="gms_core_toast_not_installed_message">GmsCore ĐŊĐĩ Đĩ иĐŊŅŅ‚Đ°ĐģĐ¸Ņ€Đ°ĐŊ. ИĐŊŅŅ‚Đ°ĐģĐ¸Ņ€Đ°ĐšŅ‚Đĩ ĐŗĐž.</string>
<string name="gms_core_dialog_title">ĐŅƒĐļĐŊĐž Đĩ Đ´ĐĩĐšŅŅ‚Đ˛Đ¸Đĩ</string> <string name="gms_core_dialog_title">ĐŅƒĐļĐŊĐž Đĩ Đ´ĐĩĐšŅŅ‚Đ˛Đ¸Đĩ</string>
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
ДоĐēĐžŅĐŊĐĩŅ‚Đĩ ĐąŅƒŅ‚ĐžĐŊа Са ĐŋŅ€ĐžĐ´ŅŠĐģĐļаваĐŊĐĩ и Ņ€Đ°ĐˇŅ€Đĩ҈ĐĩŅ‚Đĩ ĐŋŅ€ĐžĐŧĐĩĐŊи в ĐžĐŋŅ‚Đ¸ĐŧĐ¸ĐˇĐ°Ņ†Đ¸ŅŅ‚Đ°."</string> ДоĐēĐžŅĐŊĐĩŅ‚Đĩ ĐąŅƒŅ‚ĐžĐŊа Са ĐŋŅ€ĐžĐ´ŅŠĐģĐļаваĐŊĐĩ и Ņ€Đ°ĐˇŅ€Đĩ҈ĐĩŅ‚Đĩ ĐŋŅ€ĐžĐŧĐĩĐŊи в ĐžĐŋŅ‚Đ¸ĐŧĐ¸ĐˇĐ°Ņ†Đ¸ŅŅ‚Đ°."</string>
<string name="gms_core_dialog_continue_text">ĐŸŅ€ĐžĐ´ŅŠĐģĐļи</string> <string name="gms_core_dialog_continue_text">ĐŸŅ€ĐžĐ´ŅŠĐģĐļи</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">ПодĐŋŅ€Đ°Đ˛ŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸</string>
<string name="revanced_spoof_video_streams_screen_summary">ПодĐŋŅ€Đ°Đ˛ĐĩŅ‚Đĩ ĐēĐģиĐĩĐŊ҂ҁĐēĐ¸Ņ‚Đĩ видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸, Са да ĐŋŅ€ĐĩĐ´ĐžŅ‚Đ˛Ņ€Đ°Ņ‚Đ¸Ņ‚Đĩ ĐŋŅ€ĐžĐąĐģĐĩĐŧи ҁ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž</string>
<string name="revanced_spoof_video_streams_screen_title">ИĐŧĐ¸Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸</string>
<string name="revanced_spoof_video_streams_screen_summary">ИĐŧĐ¸Ņ‚Đ¸Ņ€Đ°ĐšŅ‚Đĩ видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸Ņ‚Đĩ ĐŊа ĐēĐģиĐĩĐŊŅ‚Đ°, Са да ĐŋŅ€ĐĩĐ´ĐžŅ‚Đ˛Ņ€Đ°Ņ‚Đ¸Ņ‚Đĩ ĐŋŅ€ĐžĐąĐģĐĩĐŧи ҁ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž</string>
<string name="revanced_spoof_video_streams_title">ПодĐŋŅ€Đ°Đ˛ŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸</string>
<string name="revanced_spoof_video_streams_summary_on">"ВидĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸Ņ‚Đĩ ŅĐ° ĐŋОдĐŧĐĩĐŊĐĩĐŊи
АĐēĐž ҁ҂Đĩ ĐŋĐžŅ‚Ņ€ĐĩĐąĐ¸Ņ‚ĐĩĐģ ĐŊа YouTube Premium, Ņ‚Đ°ĐˇĐ¸ ĐŊĐ°ŅŅ‚Ņ€ĐžĐšĐēа ĐŧĐžĐļĐĩ да ĐŊĐĩ Đĩ ĐŊĐĩĐžĐąŅ…ĐžĐ´Đ¸Đŧа"</string>
<string name="revanced_spoof_video_streams_summary_off">"ВидĐĩĐžĐŋĐžŅ‚ĐžŅ†Đ¸Ņ‚Đĩ ĐŊĐĩ ŅĐ° ĐŋОдĐŋŅ€Đ°Đ˛ĐĩĐŊи
Đ’ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŧĐžĐļĐĩ да ĐŊĐĩ Ņ€Đ°ĐąĐžŅ‚Đ¸"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">ИСĐēĐģŅŽŅ‡Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚Đ°ĐˇĐ¸ ĐŊĐ°ŅŅ‚Ņ€ĐžĐšĐēа ĐŧĐžĐļĐĩ да ĐŋŅ€Đ¸Ņ‡Đ¸ĐŊи ĐŋŅ€ĐžĐąĐģĐĩĐŧи ҁ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž.</string>
<string name="revanced_spoof_video_streams_client_type_title">КĐģиĐĩĐŊŅ‚ ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ</string>
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_screen_summary">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ иĐģи Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_title">ДĐŊĐĩвĐŊиĐē ĐŊа ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_summary_on">ДĐŊĐĩвĐŊиĐēŅŠŅ‚ Са ĐžŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string>
<string name="revanced_debug_summary_off">ДĐŊĐĩвĐŊиĐēŅŠŅ‚ Са ĐžŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string>
<string name="revanced_debug_export_logs_to_clipboard_title">ЕĐēҁĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">КоĐŋĐ¸Ņ€Đ° ĐģĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи ĐŊа ReVanced в ĐēĐģиĐŋĐąĐžŅ€Đ´Đ°</string>
<string name="revanced_debug_logs_disabled">ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐŗŅ€Đĩ҈Đēи Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_debug_logs_none_found">НĐĩ ŅĐ° ĐŊаĐŧĐĩŅ€ĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ</string>
<string name="revanced_debug_logs_copied_to_clipboard">Đ›ĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ ŅĐ° ĐēĐžĐŋĐ¸Ņ€Đ°ĐŊи</string>
<string name="revanced_debug_logs_failed_to_export">НĐĩ҃ҁĐŋĐĩ҈ĐŊĐž ĐĩĐēҁĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">Đ˜ĐˇŅ‡Đ¸ŅŅ‚Đ˛Đ°ĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_logs_clear_buffer_summary">Đ˜ĐˇŅ‡Đ¸ŅŅ‚Đ˛Đ° Đ˛ŅĐ¸Ņ‡Đēи ŅŅŠŅ…Ņ€Đ°ĐŊĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи ĐŊа ReVanced</string>
<string name="revanced_debug_logs_clear_toast">Đ›ĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ ŅĐ° Đ¸ĐˇŅ‡Đ¸ŅŅ‚ĐĩĐŊи</string>
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊĐžĐ˛ĐžŅ‚Đž Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩ ĐŊа Shorts Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string> <string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊĐžĐ˛ĐžŅ‚Đž Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩ ĐŊа Shorts Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
</patch> </patch>
<patch id="misc.debugging.enableDebuggingPatch"> <patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_screen_summary">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ иĐģи Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_title">ДĐŊĐĩвĐŊиĐē ĐŊа ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_summary_on">ДĐŊĐĩвĐŊиĐēŅŠŅ‚ Са ĐžŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string>
<string name="revanced_debug_summary_off">ДĐŊĐĩвĐŊиĐēŅŠŅ‚ Са ĐžŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string>
<string name="revanced_debug_protobuffer_title">Đ‘ŅƒŅ„ĐĩŅ€ ĐŊа ĐŋŅ€ĐžŅ‚ĐžĐēĐžĐģа Са Đ´ĐŊĐĩвĐŊиĐēа</string> <string name="revanced_debug_protobuffer_title">Đ‘ŅƒŅ„ĐĩŅ€ ĐŊа ĐŋŅ€ĐžŅ‚ĐžĐēĐžĐģа Са Đ´ĐŊĐĩвĐŊиĐēа</string>
<string name="revanced_debug_protobuffer_summary_on">ФаКĐģОвĐĩ ҁ Đ´ĐŊĐĩвĐŊĐ¸Ņ†Đ¸ Са ĐŗŅ€Đĩ҈Đēи вĐēĐģŅŽŅ‡Đ˛Đ°Ņ‚ ĐąŅƒŅ„ĐĩŅ€Đ°</string> <string name="revanced_debug_protobuffer_summary_on">ФаКĐģОвĐĩ ҁ Đ´ĐŊĐĩвĐŊĐ¸Ņ†Đ¸ Са ĐŗŅ€Đĩ҈Đēи вĐēĐģŅŽŅ‡Đ˛Đ°Ņ‚ ĐąŅƒŅ„ĐĩŅ€Đ°</string>
<string name="revanced_debug_protobuffer_summary_off">ФаКĐģОвĐĩ ҁ Đ´ĐŊĐĩвĐŊĐ¸Ņ†Đ¸ Са ĐŗŅ€Đĩ҈Đēи ĐŊĐĩ вĐēĐģŅŽŅ‡Đ˛Đ°Ņ‚ ĐąŅƒŅ„ĐĩŅ€Đ°</string> <string name="revanced_debug_protobuffer_summary_off">ФаКĐģОвĐĩ ҁ Đ´ĐŊĐĩвĐŊĐ¸Ņ†Đ¸ Са ĐŗŅ€Đĩ҈Đēи ĐŊĐĩ вĐēĐģŅŽŅ‡Đ˛Đ°Ņ‚ ĐąŅƒŅ„ĐĩŅ€Đ°</string>
@@ -132,15 +160,6 @@ Second \"item\" text"</string>
<string name="revanced_debug_toast_on_error_user_dialog_message">"ИСĐēĐģŅŽŅ‡Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Đ¸ĐˇŅĐēĐ°Ņ‡Đ°Ņ‰Đ¸ ŅŅŠĐžĐąŅ‰ĐĩĐŊĐ¸Ņ Са ĐŗŅ€Đĩ҈Đēи ĐēŅ€Đ¸Đĩ Đ˛ŅĐ¸Ņ‡Đēи иСвĐĩŅŅ‚Đ¸Ņ Са ĐŗŅ€Đĩ҈Đēи ĐŊа ReVanced. <string name="revanced_debug_toast_on_error_user_dialog_message">"ИСĐēĐģŅŽŅ‡Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Đ¸ĐˇŅĐēĐ°Ņ‡Đ°Ņ‰Đ¸ ŅŅŠĐžĐąŅ‰ĐĩĐŊĐ¸Ņ Са ĐŗŅ€Đĩ҈Đēи ĐēŅ€Đ¸Đĩ Đ˛ŅĐ¸Ņ‡Đēи иСвĐĩŅŅ‚Đ¸Ņ Са ĐŗŅ€Đĩ҈Đēи ĐŊа ReVanced.
ĐŅĐŧа да ĐąŅŠĐ´ĐĩŅ‚Đĩ ŅƒĐ˛ĐĩĐ´ĐžĐŧĐĩĐŊи Са ĐŊĐĩĐžŅ‡Đ°ĐēваĐŊи ŅŅŠĐąĐ¸Ņ‚Đ¸Ņ."</string> ĐŅĐŧа да ĐąŅŠĐ´ĐĩŅ‚Đĩ ŅƒĐ˛ĐĩĐ´ĐžĐŧĐĩĐŊи Са ĐŊĐĩĐžŅ‡Đ°ĐēваĐŊи ŅŅŠĐąĐ¸Ņ‚Đ¸Ņ."</string>
<string name="revanced_debug_export_logs_to_clipboard_title">ЕĐēҁĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">КоĐŋĐ¸Ņ€Đ° ĐģĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи ĐŊа ReVanced в ĐēĐģиĐŋĐąĐžŅ€Đ´Đ°</string>
<string name="revanced_debug_logs_disabled">ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐŗŅ€Đĩ҈Đēи Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_debug_logs_none_found">НĐĩ ŅĐ° ĐŊаĐŧĐĩŅ€ĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ</string>
<string name="revanced_debug_logs_copied_to_clipboard">Đ›ĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ ŅĐ° ĐēĐžĐŋĐ¸Ņ€Đ°ĐŊи</string>
<string name="revanced_debug_logs_failed_to_export">НĐĩ҃ҁĐŋĐĩ҈ĐŊĐž ĐĩĐēҁĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛Đĩ: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">Đ˜ĐˇŅ‡Đ¸ŅŅ‚Đ˛Đ°ĐŊĐĩ ĐŊа ĐģĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи</string>
<string name="revanced_debug_logs_clear_buffer_summary">Đ˜ĐˇŅ‡Đ¸ŅŅ‚Đ˛Đ° Đ˛ŅĐ¸Ņ‡Đēи ŅŅŠŅ…Ņ€Đ°ĐŊĐĩĐŊи ĐģĐžĐŗĐžĐ˛Đĩ Са ĐžŅ‚ŅŅ‚Ņ€Đ°ĐŊŅĐ˛Đ°ĐŊĐĩ ĐŊа ĐŗŅ€Đĩ҈Đēи ĐŊа ReVanced</string>
<string name="revanced_debug_logs_clear_toast">Đ›ĐžĐŗĐžĐ˛ĐĩŅ‚Đĩ ŅĐ° Đ¸ĐˇŅ‡Đ¸ŅŅ‚ĐĩĐŊи</string>
</patch> </patch>
<patch id="layout.hide.general.hideLayoutComponentsPatch"> <patch id="layout.hide.general.hideLayoutComponentsPatch">
<string name="revanced_hide_album_cards_title">\"ĐšĐ°Ņ€Ņ‚Đ¸ ĐŊа аĐģĐąŅƒĐŧĐ¸Ņ‚Đĩ\"</string> <string name="revanced_hide_album_cards_title">\"ĐšĐ°Ņ€Ņ‚Đ¸ ĐŊа аĐģĐąŅƒĐŧĐ¸Ņ‚Đĩ\"</string>
@@ -602,6 +621,10 @@ Second \"item\" text"</string>
<string name="revanced_hide_clip_button_title">Đ‘ŅƒŅ‚ĐžĐŊ Са ŅŅŠĐˇĐ´Đ°Đ˛Đ°ĐŊĐĩ ĐŊа ĐēĐģиĐŋ</string> <string name="revanced_hide_clip_button_title">Đ‘ŅƒŅ‚ĐžĐŊ Са ŅŅŠĐˇĐ´Đ°Đ˛Đ°ĐŊĐĩ ĐŊа ĐēĐģиĐŋ</string>
<string name="revanced_hide_clip_button_summary_on">Đ‘ŅƒŅ‚ĐžĐŊа Са ĐēĐģиĐŋ Đĩ ҁĐēŅ€Đ¸Ņ‚</string> <string name="revanced_hide_clip_button_summary_on">Đ‘ŅƒŅ‚ĐžĐŊа Са ĐēĐģиĐŋ Đĩ ҁĐēŅ€Đ¸Ņ‚</string>
<string name="revanced_hide_clip_button_summary_off">Đ‘ŅƒŅ‚ĐžĐŊа Са ĐēĐģиĐŋ ҁĐĩ ĐŋĐžĐēаСва</string> <string name="revanced_hide_clip_button_summary_off">Đ‘ŅƒŅ‚ĐžĐŊа Са ĐēĐģиĐŋ ҁĐĩ ĐŋĐžĐēаСва</string>
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_shop_button_title">ĐĄĐēŅ€Đ¸Đš ĐŧĐ°ĐŗĐ°ĐˇĐ¸ĐŊ</string>
<string name="revanced_hide_shop_button_summary_on">Đ‘ŅƒŅ‚ĐžĐŊŅŠŅ‚ Са ĐŧĐ°ĐŗĐ°ĐˇĐ¸ĐŊ Đĩ ҁĐēŅ€Đ¸Ņ‚</string>
<string name="revanced_hide_shop_button_summary_off">Đ‘ŅƒŅ‚ĐžĐŊŅŠŅ‚ Са ĐŧĐ°ĐŗĐ°ĐˇĐ¸ĐŊ Đĩ ĐŋĐžĐēаСаĐŊ</string>
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_save_button_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ЗаĐŋаСваĐŊĐĩ</string> <string name="revanced_hide_save_button_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ЗаĐŋаСваĐŊĐĩ</string>
<string name="revanced_hide_save_button_summary_on">Đ‘ŅƒŅ‚ĐžĐŊŅŠŅ‚ Са СаĐŋаСваĐŊĐĩ Đĩ ҁĐēŅ€Đ¸Ņ‚</string> <string name="revanced_hide_save_button_summary_on">Đ‘ŅƒŅ‚ĐžĐŊŅŠŅ‚ Са СаĐŋаСваĐŊĐĩ Đĩ ҁĐēŅ€Đ¸Ņ‚</string>
@@ -700,9 +723,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_player_flyout_audio_track_summary_on">МĐĩĐŊŅŽŅ‚Đž Са Đ¸ĐˇĐąĐžŅ€ ĐŊа ĐŅƒĐ´Đ¸Đž Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string> <string name="revanced_hide_player_flyout_audio_track_summary_on">МĐĩĐŊŅŽŅ‚Đž Са Đ¸ĐˇĐąĐžŅ€ ĐŊа ĐŅƒĐ´Đ¸Đž Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
<string name="revanced_hide_player_flyout_audio_track_summary_off">МĐĩĐŊŅŽŅ‚Đž Са Đ¸ĐˇĐąĐžŅ€ ĐŊа ĐŅƒĐ´Đ¸Đž ҁĐĩ ĐŋĐžĐēаСва</string> <string name="revanced_hide_player_flyout_audio_track_summary_off">МĐĩĐŊŅŽŅ‚Đž Са Đ¸ĐˇĐąĐžŅ€ ĐŊа ĐŅƒĐ´Đ¸Đž ҁĐĩ ĐŋĐžĐēаСва</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_hide_player_flyout_audio_track_not_available">"МĐĩĐŊŅŽŅ‚Đž Са Đ°ŅƒĐ´Đ¸Đž Ņ‚Ņ€Đ°ĐēОвĐĩ Đĩ ҁĐēŅ€Đ¸Ņ‚Đž <string name="revanced_hide_player_flyout_audio_track_not_available">"МĐĩĐŊŅŽŅ‚Đž Са Đ°ŅƒĐ´Đ¸ĐžĐˇĐ°ĐŋĐ¸Ņ Đĩ ҁĐēŅ€Đ¸Ņ‚Đž
За да ĐŋĐžĐēаĐļĐĩŅ‚Đĩ ĐŧĐĩĐŊŅŽŅ‚Đž Са Đ°ŅƒĐ´Đ¸Đž Ņ‚Ņ€Đ°ĐēОвĐĩ, ĐŋŅ€ĐžĐŧĐĩĐŊĐĩŅ‚Đĩ \"ПодĐŧŅĐŊа ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸\" ĐŊа iOS TV"</string> За да ĐŋĐžĐēаĐļĐĩŅ‚Đĩ ĐŧĐĩĐŊŅŽŅ‚Đž Са Đ°ŅƒĐ´Đ¸ĐžĐˇĐ°ĐŋĐ¸Ņ, ĐŋŅ€ĐžĐŧĐĩĐŊĐĩŅ‚Đĩ „ПодĐŋŅ€Đ°Đ˛ŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸â€œ ĐŊа iPadOS"</string>
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. --> <!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">ГĐģĐĩĐ´Đ°ĐšŅ‚Đĩ Đ˛ŅŠĐ˛ VR</string> <string name="revanced_hide_player_flyout_watch_in_vr_title">ГĐģĐĩĐ´Đ°ĐšŅ‚Đĩ Đ˛ŅŠĐ˛ VR</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">МĐĩĐŊŅŽŅ‚Đž Са ĐŗĐģĐĩдаĐŊĐĩ в VR Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string> <string name="revanced_hide_player_flyout_watch_in_vr_summary_on">МĐĩĐŊŅŽŅ‚Đž Са ĐŗĐģĐĩдаĐŊĐĩ в VR Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
@@ -1415,10 +1438,6 @@ Second \"item\" text"</string>
АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐžŅ‚ĐēĐģŅŽŅ‡Đ¸ ĐŋĐž-Đ˛Đ¸ŅĐžĐēи видĐĩĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đ°"</string> АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐžŅ‚ĐēĐģŅŽŅ‡Đ¸ ĐŋĐž-Đ˛Đ¸ŅĐžĐēи видĐĩĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đ°"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">Đ Đ°ĐˇŅ€ĐĩŅˆĐ°Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐŋŅ€Đ¸Ņ‡Đ¸ĐŊи ĐŋŅ€ĐĩĐēŅŠŅĐ˛Đ°ĐŊĐĩ ĐŊа Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŊа видĐĩĐž, вĐģĐžŅˆĐĩĐŊ ĐļĐ¸Đ˛ĐžŅ‚ ĐŊа ĐąĐ°Ņ‚ĐĩŅ€Đ¸ŅŅ‚Đ° и ĐŊĐĩиСвĐĩҁ҂ĐŊи ŅŅ‚Ņ€Đ°ĐŊĐ¸Ņ‡ĐŊи ĐĩŅ„ĐĩĐēŅ‚Đ¸.</string> <string name="revanced_spoof_device_dimensions_user_dialog_message">Đ Đ°ĐˇŅ€ĐĩŅˆĐ°Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐŋŅ€Đ¸Ņ‡Đ¸ĐŊи ĐŋŅ€ĐĩĐēŅŠŅĐ˛Đ°ĐŊĐĩ ĐŊа Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŊа видĐĩĐž, вĐģĐžŅˆĐĩĐŊ ĐļĐ¸Đ˛ĐžŅ‚ ĐŊа ĐąĐ°Ņ‚ĐĩŅ€Đ¸ŅŅ‚Đ° и ĐŊĐĩиСвĐĩҁ҂ĐŊи ŅŅ‚Ņ€Đ°ĐŊĐ¸Ņ‡ĐŊи ĐĩŅ„ĐĩĐēŅ‚Đ¸.</string>
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore ĐĐ°ŅŅ‚Ņ€ĐžĐšĐēи</string>
<string name="microg_settings_summary">ĐĐ°ŅŅ‚Ņ€ĐžĐšĐēи ĐŊа GmsCore</string>
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
<string name="revanced_disable_haptic_feedback_title">Đ’Đ¸ĐąŅ€Đ°Ņ†Đ¸ĐžĐŊĐŊа ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа</string> <string name="revanced_disable_haptic_feedback_title">Đ’Đ¸ĐąŅ€Đ°Ņ†Đ¸ĐžĐŊĐŊа ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа</string>
<string name="revanced_disable_haptic_feedback_summary">ĐŸŅ€ĐžĐŧŅĐŊа ĐŊа Đ˛Đ¸ĐąŅ€Đ°Ņ†Đ¸ĐžĐŊĐŊĐ°Ņ‚Đ° ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа</string> <string name="revanced_disable_haptic_feedback_summary">ĐŸŅ€ĐžĐŧŅĐŊа ĐŊа Đ˛Đ¸ĐąŅ€Đ°Ņ†Đ¸ĐžĐŊĐŊĐ°Ņ‚Đ° ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа</string>
@@ -1458,7 +1477,7 @@ Second \"item\" text"</string>
<string name="revanced_force_original_audio_summary_on">ИСĐŋĐžĐģСваĐŊĐĩ ĐŊа ĐžŅ€Đ¸ĐŗĐ¸ĐŊаĐģĐŊĐ¸Ņ ĐĩСиĐē ĐŊа Đ°ŅƒĐ´Đ¸ĐžŅ‚Đž</string> <string name="revanced_force_original_audio_summary_on">ИСĐŋĐžĐģСваĐŊĐĩ ĐŊа ĐžŅ€Đ¸ĐŗĐ¸ĐŊаĐģĐŊĐ¸Ņ ĐĩСиĐē ĐŊа Đ°ŅƒĐ´Đ¸ĐžŅ‚Đž</string>
<string name="revanced_force_original_audio_summary_off">ИСĐŋĐžĐģСваĐŊĐĩ ĐŊа Đ°ŅƒĐ´Đ¸Đž ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ</string> <string name="revanced_force_original_audio_summary_off">ИСĐŋĐžĐģСваĐŊĐĩ ĐŊа Đ°ŅƒĐ´Đ¸Đž ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">За да иСĐŋĐžĐģĐˇĐ˛Đ°Ņ‚Đĩ Ņ‚Đ°ĐˇĐ¸ Ņ„ŅƒĐŊĐēŅ†Đ¸Ņ, ҁĐŧĐĩĐŊĐĩŅ‚Đĩ „ФаĐģŅˆĐ¸Ņ„Đ¸Ņ†Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸â€œ ĐŊа iOS TV</string> <string name="revanced_force_original_audio_not_available">За да иСĐŋĐžĐģĐˇĐ˛Đ°Ņ‚Đĩ Ņ‚Đ°ĐˇĐ¸ Ņ„ŅƒĐŊĐēŅ†Đ¸Ņ, ĐŋŅ€ĐžĐŧĐĩĐŊĐĩŅ‚Đĩ \'ФаĐģŅˆĐ¸Ņ„Đ¸Ņ†Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸\' ĐŊа Đ˛ŅĐĩĐēи ĐēĐģиĐĩĐŊŅ‚, ĐžŅĐ˛ĐĩĐŊ Android Studio</string>
</patch> </patch>
<patch id="video.quality.rememberVideoQualityPatch"> <patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. --> <!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1532,35 +1551,54 @@ Second \"item\" text"</string>
<string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Са ĐŋŅ€ĐĩĐ˛ŅŠŅ€Ņ‚Đ°ĐŊĐĩ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string> <string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Са ĐŋŅ€ĐĩĐ˛ŅŠŅ€Ņ‚Đ°ĐŊĐĩ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">ПодĐŋŅ€Đ°Đ˛ŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸</string> <string name="revanced_spoof_video_streams_about_title">ĐĄŅ‚Ņ€Đ°ĐŊĐ¸Ņ‡ĐŊи ĐĩŅ„ĐĩĐēŅ‚Đ¸ ĐžŅ‚ ĐŋОдĐŧĐĩĐŊŅĐŊĐĩŅ‚Đž</string>
<string name="revanced_spoof_video_streams_screen_summary">ПодĐŋŅ€Đ°Đ˛ĐĩŅ‚Đĩ ĐēĐģиĐĩĐŊ҂ҁĐēĐ¸Ņ‚Đĩ видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸, Са да ĐŋŅ€ĐĩĐ´ĐžŅ‚Đ˛Ņ€Đ°Ņ‚Đ¸Ņ‚Đĩ ĐŋŅ€ĐžĐąĐģĐĩĐŧи ҁ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž</string>
<string name="revanced_spoof_video_streams_title">ПодĐŋŅ€Đ°Đ˛ŅĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸</string>
<string name="revanced_spoof_video_streams_summary_on">ВидĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸Ņ‚Đĩ ŅĐ° ĐŋОдĐŋŅ€Đ°Đ˛ĐĩĐŊи</string>
<string name="revanced_spoof_video_streams_summary_off">"ĐŸĐžŅ‚ĐžŅ†Đ¸Ņ‚Đĩ ĐŊа видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŊĐĩ ŅĐ° Ņ„Đ°ĐģŅˆĐ¸Ņ„Đ¸Ņ†Đ¸Ņ€Đ°ĐŊи
Đ’ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŊа видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ Ņ€Đ°ĐąĐžŅ‚Đ¸"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">ДĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚Đ°ĐˇĐ¸ ĐŊĐ°ŅŅ‚Ņ€ĐžĐšĐēа ҉Đĩ дОвĐĩĐ´Đĩ Đ´Đž ĐŋŅ€ĐžĐąĐģĐĩĐŧи ҁ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŊа видĐĩĐž.</string>
<string name="revanced_spoof_video_streams_client_type_title">КĐģиĐĩĐŊŅ‚ ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ</string>
<string name="revanced_spoof_video_streams_ios_force_avc_title">ĐŸŅ€Đ¸ĐŊŅƒĐ´Đ¸Ņ‚ĐĩĐģĐŊĐž иСĐŋĐžĐģСваĐŊĐĩ ĐŊа AVC (H.264) ĐŊа iOS</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">ВидĐĩĐž ĐēОдĐĩĐēŅŠŅ‚ Đĩ ĐŋŅ€Đ¸ĐŊŅƒĐ´Đ¸Ņ‚ĐĩĐģĐŊĐž СададĐĩĐŊ ĐŊа AVC (H.264)</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">ВидĐĩĐž ĐēОдĐĩĐēŅŠŅ‚ ҁĐĩ ĐžĐŋŅ€ĐĩĐ´ĐĩĐģŅ Đ°Đ˛Ņ‚ĐžĐŧĐ°Ņ‚Đ¸Ņ‡ĐŊĐž</string>
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"ВĐēĐģŅŽŅ‡Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐŋĐžĐ´ĐžĐąŅ€Đ¸ ĐļĐ¸Đ˛ĐžŅ‚Đ° ĐŊа ĐąĐ°Ņ‚ĐĩŅ€Đ¸ŅŅ‚Đ° и да ĐŋĐžĐŋŅ€Đ°Đ˛Đ¸ СаĐĩĐēваĐŊĐĩŅ‚Đž ĐŋŅ€Đ¸ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩ.
AVC иĐŧа ĐŧаĐēŅĐ¸ĐŧаĐģĐŊа Ņ€ĐĩСОĐģŅŽŅ†Đ¸Ņ ĐžŅ‚ 1080p, Opus Đ°ŅƒĐ´Đ¸Đž ĐēОдĐĩĐē ĐŊĐĩ Đĩ ĐŊаĐģĐ¸Ņ‡ĐĩĐŊ и Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŊа видĐĩĐž ҉Đĩ иСĐŋĐžĐģСва ĐŋОвĐĩ҇Đĩ иĐŊŅ‚ĐĩŅ€ĐŊĐĩŅ‚ даĐŊĐŊи ĐžŅ‚ VP9 иĐģи AV1."</string>
<string name="revanced_spoof_video_streams_about_ios_tv_title">Đ•Ņ„ĐĩĐēŅ‚Đ¸ ĐŊа иСĐŧаĐŧĐ°Ņ‚Đ° в iOS</string>
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"â€ĸ ФиĐģĐŧи иĐģи ĐŋĐģĐ°Ņ‚ĐĩĐŊи видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ ҁĐĩ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļĐ´Đ°Ņ‚
â€ĸ ĐĄŅ‚Đ°ĐąĐ¸ĐģĐĩĐŊ ĐˇĐ˛ŅƒĐē ĐŊĐĩ Đĩ ĐŊаĐģĐ¸Ņ‡ĐĩĐŊ
â€ĸ ВидĐĩĐžĐēĐģиĐŋОвĐĩŅ‚Đĩ ĐˇĐ°Đ˛ŅŠŅ€ŅˆĐ˛Đ°Ņ‚ 1 ҁĐĩĐē҃ĐŊда ĐŋĐž-Ņ€Đ°ĐŊĐž"</string>
<string name="revanced_spoof_video_streams_about_android_title">Strani4ni efekti na fal6ivoto predstavqne na Android</string> <string name="revanced_spoof_video_streams_about_android_title">Strani4ni efekti na fal6ivoto predstavqne na Android</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Lipsva menju za audio pisti <string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ ЛиĐŋŅĐ˛Đ° ĐŧĐĩĐŊŅŽŅ‚Đž Са Đ°ŅƒĐ´Đ¸ĐžĐˇĐ°ĐŋĐ¸ŅĐ¸
â€ĸ Ne e nali4na stabilna glasnost â€ĸ ĐĄŅ‚Đ°ĐąĐ¸ĐģĐĩĐŊ ĐˇĐ˛ŅƒĐē ĐŊĐĩ Đĩ ĐŊаĐģĐ¸Ņ‡ĐĩĐŊ"</string>
â€ĸ Ne e nali4na forsirana originalna audio pista"</string> <string name="revanced_spoof_video_streams_about_ipados_summary">â€ĸ ВидĐĩĐžŅ‚Đž ĐŧĐžĐļĐĩ да ҁĐŋŅ€Đĩ ĐŊа 1:00 иĐģи ĐŧĐžĐļĐĩ да ĐŊĐĩ Đĩ ĐŊаĐģĐ¸Ņ‡ĐŊĐž в ĐŊŅĐēОи Ņ€ĐĩĐŗĐ¸ĐžĐŊи</string>
<string name="revanced_spoof_video_streams_about_experimental">â€ĸ ЕĐēҁĐŋĐĩŅ€Đ¸ĐŧĐĩĐŊŅ‚Đ°ĐģĐĩĐŊ ĐēĐģиĐĩĐŊŅ‚ и ĐŧĐžĐļĐĩ да ҁĐŋŅ€Đĩ да Ņ€Đ°ĐąĐžŅ‚Đ¸ ĐŋĐž Đ˛ŅŅĐēĐž Đ˛Ņ€ĐĩĐŧĐĩ</string>
<string name="revanced_spoof_video_streams_about_no_av1">â€ĸ БĐĩС AV1 видĐĩĐž ĐēОдĐĩĐē</string> <string name="revanced_spoof_video_streams_about_no_av1">â€ĸ БĐĩС AV1 видĐĩĐž ĐēОдĐĩĐē</string>
<string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ ДĐĩ҂ҁĐēĐ¸Ņ‚Đĩ видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ ҁĐĩ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļĐ´Đ°Ņ‚, ĐēĐžĐŗĐ°Ņ‚Đž ҁ҂Đĩ иСĐģĐĩСĐģи ĐžŅ‚ ĐŋŅ€ĐžŅ„Đ¸Đģа ŅĐ¸ иĐģи в Ņ€ĐĩĐļиĐŧ \"иĐŊĐēĐžĐŗĐŊĐ¸Ņ‚Đž\"</string> <string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ ДĐĩ҂ҁĐēĐ¸Ņ‚Đĩ видĐĩĐžĐēĐģиĐŋОвĐĩ ĐŧĐžĐļĐĩ да ĐŊĐĩ ҁĐĩ Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļĐ´Đ°Ņ‚, ĐēĐžĐŗĐ°Ņ‚Đž ҁ҂Đĩ иСĐģĐĩСĐģи ĐžŅ‚ ĐŋŅ€ĐžŅ„Đ¸Đģа ŅĐ¸ иĐģи в Ņ€ĐĩĐļиĐŧ \"иĐŊĐēĐžĐŗĐŊĐ¸Ņ‚Đž\"</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Poka6i v Statistiki za nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">Poka6i v Statistiki za nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">TipŅŠŅ‚ na klienta se poka6va v Statistiki za nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">TipŅŠŅ‚ na klienta se poka6va v Statistiki za nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">KlientŅŠŅ‚ e skriŅ‚ v Statistiki za nerds</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">KlientŅŠŅ‚ e skriŅ‚ v Statistiki za nerds</string>
<string name="revanced_spoof_video_streams_language_title">Ezik po ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ za audio potok v VR</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>
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
<string name="revanced_settings_music_screen_0_about_title">ĐžŅ‚ĐŊĐžŅĐŊĐž</string>
<string name="revanced_settings_music_screen_1_ads_title">Đ ĐĩĐēĐģаĐŧи</string>
<string name="revanced_settings_music_screen_2_general_title">ĐžĐąŅ‰Đ¸</string>
<string name="revanced_settings_music_screen_3_player_title">ПĐģĐĩĐšŅŠŅ€</string>
<string name="revanced_settings_music_screen_4_misc_title">РаСĐŊи</string>
</patch>
<patch id="ad.video.hideVideoAdsPatch">
<string name="revanced_music_hide_video_ads_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа видĐĩĐžŅ€ĐĩĐēĐģаĐŧи</string>
<string name="revanced_music_hide_video_ads_summary_on">ВидĐĩĐžŅ€ĐĩĐēĐģаĐŧĐ¸Ņ‚Đĩ ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸</string>
<string name="revanced_music_hide_video_ads_summary_off">ВидĐĩĐžŅ€ĐĩĐēĐģаĐŧĐ¸Ņ‚Đĩ ŅĐ° ĐŋĐžĐēаСаĐŊи</string>
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
<string name="revanced_music_play_permanent_repeat_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐŋĐžŅŅ‚ĐžŅĐŊĐŊĐž ĐŋĐžĐ˛Ņ‚Đ°Ņ€ŅĐŊĐĩ</string>
<string name="revanced_music_play_permanent_repeat_summary_on">ĐŸĐžŅŅ‚ĐžŅĐŊĐŊĐžŅ‚Đž ĐŋĐžĐ˛Ņ‚Đ°Ņ€ŅĐŊĐĩ Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_music_play_permanent_repeat_summary_off">ĐŸĐžŅŅ‚ĐžŅĐŊĐŊĐžŅ‚Đž ĐŋĐžĐ˛Ņ‚Đ°Ņ€ŅĐŊĐĩ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
</patch>
<patch id="layout.compactheader.hideCategoryBar">
<string name="revanced_music_hide_category_bar_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ĐģĐĩĐŊŅ‚Đ°Ņ‚Đ° ҁ ĐēĐ°Ņ‚ĐĩĐŗĐžŅ€Đ¸Đ¸</string>
<string name="revanced_music_hide_category_bar_summary_on">ЛĐĩĐŊŅ‚Đ°Ņ‚Đ° ҁ ĐēĐ°Ņ‚ĐĩĐŗĐžŅ€Đ¸Đ¸ Đĩ ҁĐēŅ€Đ¸Ņ‚Đ°</string>
<string name="revanced_music_hide_category_bar_summary_off">ЛĐĩĐŊŅ‚Đ°Ņ‚Đ° ҁ ĐēĐ°Ņ‚ĐĩĐŗĐžŅ€Đ¸Đ¸ Đĩ ĐŋĐžĐēаСаĐŊа</string>
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ĐĩŅ‚Đ¸ĐēĐĩŅ‚Đ° „ВзĐĩĐŧĐĩŅ‚Đĩ Music Premium“</string>
<string name="revanced_music_hide_get_premium_label_summary_on">Đ•Ņ‚Đ¸ĐēĐĩŅ‚ŅŠŅ‚ Đĩ ҁĐēŅ€Đ¸Ņ‚</string>
<string name="revanced_music_hide_get_premium_label_summary_off">Đ•Ņ‚Đ¸ĐēĐĩŅ‚ŅŠŅ‚ Đĩ ĐŋĐžĐēаСаĐŊ</string>
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
<string name="revanced_music_hide_upgrade_button_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ĐąŅƒŅ‚ĐžĐŊа Са ĐŊĐ°Đ´ŅŅ‚Ņ€ĐžĐšĐēа</string>
<string name="revanced_music_hide_upgrade_button_summary_on">Đ‘ŅƒŅ‚ĐžĐŊŅŠŅ‚ Đĩ ҁĐēŅ€Đ¸Ņ‚</string>
<string name="revanced_music_hide_upgrade_button_summary_off">Đ‘ŅƒŅ‚ĐžĐŊŅŠŅ‚ Đĩ ĐŋĐžĐēаСаĐŊ</string>
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. --> and changes made here must also be made there. -->
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch"> <patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore āϏ⧇āϟāĻŋāĻ‚</string>
<string name="microg_settings_summary">GmsCore āĻāϰ āϜāĻ¨ā§āϝ āϏ⧇āϟāĻŋāĻ‚</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. --> <!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<string name="gms_core_toast_not_installed_message">MicroG GmsCore āχāύāĻ¸ā§āϟāϞ āĻ•āϰāĻž āĻšā§ŸāύāĻŋāĨ¤ āχāύāĻ¸ā§āϟāϞ āĻ•āϰ⧁āύāĨ¤</string> <string name="gms_core_toast_not_installed_message">MicroG GmsCore āχāύāĻ¸ā§āϟāϞ āĻ•āϰāĻž āĻšā§ŸāύāĻŋāĨ¤ āχāύāĻ¸ā§āϟāϞ āĻ•āϰ⧁āύāĨ¤</string>
<string name="gms_core_dialog_title">āĻĒāĻĻāĻ•ā§āώ⧇āĻĒ āĻĒā§āĻ°ā§Ÿā§‹āϜāύ</string> <string name="gms_core_dialog_title">āĻĒāĻĻāĻ•ā§āώ⧇āĻĒ āĻĒā§āĻ°ā§Ÿā§‹āϜāύ</string>
@@ -84,6 +86,37 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
āϚāĻžāϞāĻŋāϝāĻŧ⧇ āϝāĻžāύ āĻŦā§‹āϤāĻžāĻŽāϟāĻŋ āĻŸā§āϝāĻžāĻĒ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāĻœā§‡āĻļāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞāĻŋ āĻ…āύ⧁āĻŽā§‹āĻĻāύ āĻ•āϰ⧁āύāĨ¤"</string> āϚāĻžāϞāĻŋāϝāĻŧ⧇ āϝāĻžāύ āĻŦā§‹āϤāĻžāĻŽāϟāĻŋ āĻŸā§āϝāĻžāĻĒ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāĻœā§‡āĻļāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞāĻŋ āĻ…āύ⧁āĻŽā§‹āĻĻāύ āĻ•āϰ⧁āύāĨ¤"</string>
<string name="gms_core_dialog_continue_text">āĻāĻ—āĻŋā§Ÿā§‡ āϝāĻžāύ</string> <string name="gms_core_dialog_continue_text">āĻāĻ—āĻŋā§Ÿā§‡ āϝāĻžāύ</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽāĻŋāĻ‚ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_screen_summary">āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āϏāĻŽāĻ¸ā§āϝāĻž āĻĒā§āϰāϤāĻŋāϰ⧋āϧ āĻ•āϰāϤ⧇ āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_screen_title">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_screen_summary">āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āϏāĻ‚āĻ•ā§āϰāĻžāĻ¨ā§āϤ āϏāĻŽāĻ¸ā§āϝāĻž āϰ⧋āϧ āĻ•āϰāϤ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āĻŸā§‡āϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽāϗ⧁āϞāĻŋ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_title">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽāĻŋāĻ‚ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_summary_on">"āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇
āφāĻĒāύāĻŋ āϝāĻĻāĻŋ YouTube Premium āĻŦā§āϝāĻŦāĻšāĻžāϰāĻ•āĻžāϰ⧀ āĻšāύ, āϤāĻžāĻšāϞ⧇ āĻāχ āϏ⧇āϟāĻŋāĻ‚āϟāĻŋāϰ āĻĒā§āϰāϝāĻŧā§‹āϜāύ āύāĻžāĻ“ āĻšāϤ⧇ āĻĒāĻžāϰ⧇"</string>
<string name="revanced_spoof_video_streams_summary_off">"āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰāĻž āĻšāϝāĻŧāύāĻŋ
āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻ•āĻžāϜ āύāĻžāĻ“ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">āĻāχ āϏ⧇āϟāĻŋāĻ‚ āĻŦāĻ¨ā§āϧ āĻ•āϰāϞ⧇ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āϏāĻŽāĻ¸ā§āϝāĻž āĻšāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤</string>
<string name="revanced_spoof_video_streams_client_type_title">āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ</string>
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">āĻĄāĻŋāĻŦāĻžāĻ—āĻŋāĻ‚</string>
<string name="revanced_debug_screen_summary">āĻĄāĻŋāĻŦāĻžāĻ—āĻŋāĻ‚ āĻ…āĻĒāĻļāύ āϏāĻ•ā§āϰāĻŋ⧟ āĻŦāĻž āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_debug_title">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āĻŋāĻ‚</string>
<string name="revanced_debug_summary_on">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āϏāĻ•ā§āϰāĻŋ⧟ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_debug_summary_off">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_debug_export_logs_to_clipboard_title">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āϗ⧁āϞāĻŋ āϰāĻĢāϤāĻžāύāĻŋ āĻ•āϰ⧁āύ</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">āĻ•ā§āϞāĻŋāĻĒāĻŦā§‹āĻ°ā§āĻĄā§‡ ReVanced āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āϗ⧁āϞāĻŋ āĻ…āύ⧁āϞāĻŋāĻĒāĻŋ āĻ•āϰ⧇</string>
<string name="revanced_debug_logs_disabled">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āĻŋāĻ‚ āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_debug_logs_none_found">āϕ⧋āύ⧋ āϞāĻ— āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧāύāĻŋ</string>
<string name="revanced_debug_logs_copied_to_clipboard">āϞāĻ— āĻ…āύ⧁āϞāĻŋāĻĒāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_debug_logs_failed_to_export">āϞāĻ— āĻāĻ•ā§āϏāĻĒā§‹āĻ°ā§āϟ āĻ•āϰāĻž āϝāĻžāϝāĻŧāύāĻŋ: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āϗ⧁āϞāĻŋ āϏāĻžāĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_debug_logs_clear_buffer_summary">āϏāĻŽāĻ¸ā§āϤ āϏāĻžā§āϚāĻŋāϤ ReVanced āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āϏāĻžāĻĢ āĻ•āϰ⧇</string>
<string name="revanced_debug_logs_clear_toast">āϞāĻ— āϏāĻžāĻĢ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
</patch>
</app> </app>
<app id="youtube"> <app id="youtube">
<patch id="misc.settings.settingsPatch"> <patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts āĻŦā§āϝāĻžāĻ•āĻ—ā§āϰāĻžāωāĻ¨ā§āĻĄ āĻĒā§āϞ⧇ āϏāĻ•ā§āώāĻŽ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string> <string name="revanced_shorts_disable_background_playback_summary_off">Shorts āĻŦā§āϝāĻžāĻ•āĻ—ā§āϰāĻžāωāĻ¨ā§āĻĄ āĻĒā§āϞ⧇ āϏāĻ•ā§āώāĻŽ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
</patch> </patch>
<patch id="misc.debugging.enableDebuggingPatch"> <patch id="misc.debugging.enableDebuggingPatch">
<string name="revanced_debug_screen_title">āĻĄāĻŋāĻŦāĻžāĻ—āĻŋāĻ‚</string>
<string name="revanced_debug_screen_summary">āĻĄāĻŋāĻŦāĻžāĻ—āĻŋāĻ‚ āĻ…āĻĒāĻļāύ āϏāĻ•ā§āϰāĻŋ⧟ āĻŦāĻž āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_debug_title">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āĻŋāĻ‚</string>
<string name="revanced_debug_summary_on">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āϏāĻ•ā§āϰāĻŋ⧟ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_debug_summary_off">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_debug_protobuffer_title">āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϞāĻ—</string> <string name="revanced_debug_protobuffer_title">āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϞāĻ—</string>
<string name="revanced_debug_protobuffer_summary_on">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻŦ⧇</string> <string name="revanced_debug_protobuffer_summary_on">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻŦ⧇</string>
<string name="revanced_debug_protobuffer_summary_off">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻŦ⧇ āύāĻž</string> <string name="revanced_debug_protobuffer_summary_off">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻŦ⧇ āύāĻž</string>
@@ -128,15 +156,6 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_debug_toast_on_error_user_dialog_message">"āĻ¤ā§āϰ⧁āϟāĻŋ \"toast\" āĻŦāĻ¨ā§āϧ āĻ•āϰ⧇ ReVanced āĻ¤ā§āϰ⧁āϟāĻŋ āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋāϗ⧁āϞāĻŋ āϞ⧁āĻ•āĻžāύ⧋ āĻšāϝāĻŧāĨ¤ <string name="revanced_debug_toast_on_error_user_dialog_message">"āĻ¤ā§āϰ⧁āϟāĻŋ \"toast\" āĻŦāĻ¨ā§āϧ āĻ•āϰ⧇ ReVanced āĻ¤ā§āϰ⧁āϟāĻŋ āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋāϗ⧁āϞāĻŋ āϞ⧁āĻ•āĻžāύ⧋ āĻšāϝāĻŧāĨ¤
āφāĻĒāύāĻŋ āϕ⧋āύāĻ“ āĻ…āĻĒā§āϰāĻ¤ā§āϝāĻžāĻļāĻŋāϤ āϘāϟāύāĻžāϰ āĻŦāĻŋāώāϝāĻŧ⧇ āĻ…āĻŦāĻšāĻŋāϤ āĻšāĻŦ⧇āύ āύāĻžāĨ¤"</string> āφāĻĒāύāĻŋ āϕ⧋āύāĻ“ āĻ…āĻĒā§āϰāĻ¤ā§āϝāĻžāĻļāĻŋāϤ āϘāϟāύāĻžāϰ āĻŦāĻŋāώāϝāĻŧ⧇ āĻ…āĻŦāĻšāĻŋāϤ āĻšāĻŦ⧇āύ āύāĻžāĨ¤"</string>
<string name="revanced_debug_export_logs_to_clipboard_title">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āϗ⧁āϞāĻŋ āϰāĻĢāϤāĻžāύāĻŋ āĻ•āϰ⧁āύ</string>
<string name="revanced_debug_export_logs_to_clipboard_summary">āĻ•ā§āϞāĻŋāĻĒāĻŦā§‹āĻ°ā§āĻĄā§‡ ReVanced āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āϗ⧁āϞāĻŋ āĻ…āύ⧁āϞāĻŋāĻĒāĻŋ āĻ•āϰ⧇</string>
<string name="revanced_debug_logs_disabled">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āĻŋāĻ‚ āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_debug_logs_none_found">āϕ⧋āύ⧋ āϞāĻ— āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧāύāĻŋ</string>
<string name="revanced_debug_logs_copied_to_clipboard">āϞāĻ— āĻ…āύ⧁āϞāĻŋāĻĒāĻŋ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_debug_logs_failed_to_export">āϞāĻ— āĻāĻ•ā§āϏāĻĒā§‹āĻ°ā§āϟ āĻ•āϰāĻž āϝāĻžāϝāĻŧāύāĻŋ: %s</string>
<string name="revanced_debug_logs_clear_buffer_title">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ—āϗ⧁āϞāĻŋ āϏāĻžāĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_debug_logs_clear_buffer_summary">āϏāĻŽāĻ¸ā§āϤ āϏāĻžā§āϚāĻŋāϤ ReVanced āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āϏāĻžāĻĢ āĻ•āϰ⧇</string>
<string name="revanced_debug_logs_clear_toast">āϞāĻ— āϏāĻžāĻĢ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
</patch> </patch>
<patch id="layout.hide.general.hideLayoutComponentsPatch"> <patch id="layout.hide.general.hideLayoutComponentsPatch">
<string name="revanced_hide_album_cards_title">āĻ…ā§āϝāĻžāϞāĻŦāĻžāĻŽ āĻ•āĻžāĻ°ā§āĻĄ āϞ⧁āĻ•āĻžāύ</string> <string name="revanced_hide_album_cards_title">āĻ…ā§āϝāĻžāϞāĻŦāĻžāĻŽ āĻ•āĻžāĻ°ā§āĻĄ āϞ⧁āĻ•āĻžāύ</string>
@@ -598,6 +617,10 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_clip_button_title">āĻ•ā§āϞāĻŋāĻĒ āϞ⧁āĻ•āĻžāύ</string> <string name="revanced_hide_clip_button_title">āĻ•ā§āϞāĻŋāĻĒ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_clip_button_summary_on">āĻ•ā§āϞāĻŋāĻĒ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string> <string name="revanced_hide_clip_button_summary_on">āĻ•ā§āϞāĻŋāĻĒ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_clip_button_summary_off">āĻ•ā§āϞāĻŋāĻĒ āĻŦā§‹āϤāĻžāĻŽ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string> <string name="revanced_hide_clip_button_summary_off">āĻ•ā§āϞāĻŋāĻĒ āĻŦā§‹āϤāĻžāĻŽ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<!-- 'Shop' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_shop_button_title">āĻļāĻĒ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_shop_button_summary_on">āĻļāĻĒ āĻŦāĻžāϟāύ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_shop_button_summary_off">āĻļāĻĒ āĻŦāĻžāϟāύ āĻĻ⧇āĻ–āĻžāύ⧋ āφāϛ⧇</string>
<!-- 'Save' should be translated with the same localized wording that YouTube displays. --> <!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_save_button_title">āϏāĻ‚āϰāĻ•ā§āώāĻŖ āϞ⧁āĻ•āĻžāύ</string> <string name="revanced_hide_save_button_title">āϏāĻ‚āϰāĻ•ā§āώāĻŖ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_save_button_summary_on">āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string> <string name="revanced_hide_save_button_summary_on">āϏāĻ‚āϰāĻ•ā§āώāĻŖ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
@@ -698,7 +721,7 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_hide_player_flyout_audio_track_not_available">"āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇ <string name="revanced_hide_player_flyout_audio_track_not_available">"āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇
āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āĻĻ⧇āĻ–āĻžāϤ⧇, 'āĻ¸ā§āĻĒ⧁āĻĢ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ' āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧇ iOS TV āĻ•āϰ⧁āύ"</string> āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āĻĻ⧇āĻ–āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ, 'āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ' āϕ⧇ iPadOS āĻ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ"</string>
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. --> <!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">āĻ­āĻŋāφāϰ-āĻ āϘāĻĄāĻŧāĻŋ āϞ⧁āĻ•āĻžāύ</string> <string name="revanced_hide_player_flyout_watch_in_vr_title">āĻ­āĻŋāφāϰ-āĻ āϘāĻĄāĻŧāĻŋ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">āĻ­āĻŋāφāϰ āĻŽā§‡āύ⧁āϤ⧇ āĻĻ⧇āϖ⧁āύ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string> <string name="revanced_hide_player_flyout_watch_in_vr_summary_on">āĻ­āĻŋāφāϰ āĻŽā§‡āύ⧁āϤ⧇ āĻĻ⧇āϖ⧁āύ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
@@ -1411,10 +1434,6 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
āĻāϟāĻŋ āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āωāĻšā§āϚ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύāϗ⧁āϞāĻŋ āφāύāϞāĻ• āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇"</string> āĻāϟāĻŋ āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āωāĻšā§āϚ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύāϗ⧁āϞāĻŋ āφāύāϞāĻ• āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">āĻāϟāĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻžāϰ āĻĢāϞ⧇ āφāĻĒāύāĻŋ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāϞāĻžāϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ āφāϟāϕ⧇ āϚāϞāĻž, āĻ–āĻžāϰāĻžāĻĒ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āϞāĻžāχāĻĢ āĻāĻŦāĻ‚ āĻ…āϜāĻžāύāĻž āĻĒāĻžāĻ°ā§āĻļā§āĻŦ-āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻžāϰ āϏāĻŽā§āĻŽā§āĻ–āĻŋāύ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤</string> <string name="revanced_spoof_device_dimensions_user_dialog_message">āĻāϟāĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻžāϰ āĻĢāϞ⧇ āφāĻĒāύāĻŋ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāϞāĻžāϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ āφāϟāϕ⧇ āϚāϞāĻž, āĻ–āĻžāϰāĻžāĻĒ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āϞāĻžāχāĻĢ āĻāĻŦāĻ‚ āĻ…āϜāĻžāύāĻž āĻĒāĻžāĻ°ā§āĻļā§āĻŦ-āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻžāϰ āϏāĻŽā§āĻŽā§āĻ–āĻŋāύ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤</string>
</patch> </patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
<string name="microg_settings_title">GmsCore āϏ⧇āϟāĻŋāĻ‚</string>
<string name="microg_settings_summary">GmsCore āĻāϰ āϜāĻ¨ā§āϝ āϏ⧇āϟāĻŋāĻ‚</string>
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch"> <patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
<string name="revanced_disable_haptic_feedback_title">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻž</string> <string name="revanced_disable_haptic_feedback_title">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻž</string>
<string name="revanced_disable_haptic_feedback_summary">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻž āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string> <string name="revanced_disable_haptic_feedback_summary">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻž āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
@@ -1454,7 +1473,7 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
<string name="revanced_force_original_audio_summary_on">āĻŽā§‚āϞ āĻ…āĻĄāĻŋāĻ“ āĻ­āĻžāώāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻšāĻšā§āϛ⧇</string> <string name="revanced_force_original_audio_summary_on">āĻŽā§‚āϞ āĻ…āĻĄāĻŋāĻ“ āĻ­āĻžāώāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻšāĻšā§āϛ⧇</string>
<string name="revanced_force_original_audio_summary_off">āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ…āĻĄāĻŋāĻ“ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϛ⧇</string> <string name="revanced_force_original_audio_summary_off">āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ…āĻĄāĻŋāĻ“ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϛ⧇</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. --> <!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">āĻāχ āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇, \'āĻ¸ā§āĻĒ⧁āĻĢ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰ⧀āĻŽ\' āϕ⧇ iOS TV-āϤ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string> <string name="revanced_force_original_audio_not_available">āĻāχ āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇, \'āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ\' āĻ…ā§āϝāĻžāĻ¨ā§āĻĄā§āϰāϝāĻŧ⧇āĻĄ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“ āĻ›āĻžāĻĄāĻŧāĻž āĻ…āĻ¨ā§āϝ āϕ⧋āύ⧋ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āĻŸā§‡ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
</patch> </patch>
<patch id="video.quality.rememberVideoQualityPatch"> <patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. --> <!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1528,35 +1547,54 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
<string name="revanced_slide_to_seek_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ‚āĻļ⧇ āϝ⧇āϤ⧇ āϟāĻžāύ⧁āύ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§ŸāύāĻŋ</string> <string name="revanced_slide_to_seek_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ‚āĻļ⧇ āϝ⧇āϤ⧇ āϟāĻžāύ⧁āύ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§ŸāύāĻŋ</string>
</patch> </patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch"> <patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽāĻŋāĻ‚ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string> <string name="revanced_spoof_video_streams_about_title">āĻ¸ā§āĻĒ⧁āĻĢāĻŋāĻ‚ā§Ÿā§‡āϰ āĻĒāĻžāĻ°ā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž</string>
<string name="revanced_spoof_video_streams_screen_summary">āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āϏāĻŽāĻ¸ā§āϝāĻž āĻĒā§āϰāϤāĻŋāϰ⧋āϧ āĻ•āϰāϤ⧇ āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_title">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽāĻŋāĻ‚ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_summary_on">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_spoof_video_streams_summary_off">"āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āϭ⧁āϝāĻŧāĻž āύāϝāĻŧ
āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻ•āĻžāϜ āύāĻžāĻ“ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇"</string>
<string name="revanced_spoof_video_streams_user_dialog_message">āĻāχ āϏ⧇āϟāĻŋāĻ‚āϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰāĻžāϰ āĻĢāϞ⧇ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻ¤ā§āϰ⧁āϟāĻŋ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤</string>
<string name="revanced_spoof_video_streams_client_type_title">āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ</string>
<string name="revanced_spoof_video_streams_ios_force_avc_title">iOS AVC (H.264) āĻŦāĻžāĻ§ā§āϝāϤāĻžāĻŽā§‚āϞāĻ• āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_on">āĻ­āĻŋāĻĄāĻŋāĻ“ āϕ⧋āĻĄā§‡āĻ• AVC (H.264) āĻ āĻŦāĻžāĻ§ā§āϝāϤāĻžāĻŽā§‚āϞāĻ• āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_spoof_video_streams_ios_force_avc_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“ āϕ⧋āĻĄā§‡āĻ• āĻ¸ā§āĻŦāϝāĻŧāĻ‚āĻ•ā§āϰāĻŋāϝāĻŧāĻ­āĻžāĻŦ⧇ āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ āĻšā§Ÿ</string>
<string name="revanced_spoof_video_streams_ios_force_avc_user_dialog_message">"āĻāϟāĻŋ āϏāĻ•ā§āώāĻŽ āĻ•āϰāϞ⧇ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āϞāĻžāχāĻĢ āωāĻ¨ā§āύāϤ āĻšāϤ⧇ āĻĒāĻžāϰ⧇ āĻāĻŦāĻ‚ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻ¸ā§āϟāĻžāϟāĻžāϰāĻŋāĻ‚ āϏāĻŽāĻ¸ā§āϝāĻž āϏāĻŽāĻžāϧāĻžāύ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤
AVC-āĻāϰ āϏāĻ°ā§āĻŦā§‹āĻšā§āϚ āϰ⧇āĻœā§‹āϞāĻŋāωāĻļāύ āĻšāϞ 1080p, Opus āĻ…āĻĄāĻŋāĻ“ āϕ⧋āĻĄā§‡āĻ• āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž āĻāĻŦāĻ‚ VP9 āĻŦāĻž AV1-āĻāϰ āϤ⧁āϞāύāĻžāϝāĻŧ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāϕ⧇ āĻŦ⧇āĻļāĻŋ āχāĻ¨ā§āϟāĻžāϰāύ⧇āϟ āĻĄā§‡āϟāĻž āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āĻšāĻŦā§‡ã€‚"</string>
<string name="revanced_spoof_video_streams_about_ios_tv_title">āφāχāĻ“āĻāϏ āĻ¸ā§āĻĒ⧁āĻĢāĻŋāĻ‚āϝāĻŧ⧇āϰ āĻĒāĻžāĻ°ā§āĻļā§āĻŦ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž</string>
<string name="revanced_spoof_video_streams_about_ios_tv_summary">"â€ĸ āĻŽā§āĻ­āĻŋ āĻŦāĻž āĻ…āĻ°ā§āĻĨ āĻĒā§āϰāĻĻāĻžāύ⧇āϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāĻžāϞ⧁ āύāĻžāĻ“ āĻšāϤ⧇ āĻĒāĻžāϰ⧇
â€ĸ āĻ¸ā§āĻĨāĻŋāϰ āĻ­āϞāĻŋāωāĻŽ āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž
â€ĸ āĻ­āĻŋāĻĄāĻŋāĻ“āϗ⧁āϞāĻŋ 1 āϏ⧇āϕ⧇āĻ¨ā§āĻĄ āφāϗ⧇ āĻļ⧇āώ āĻšāϝāĻŧ⧇ āϝāĻžāϝāĻŧ"</string>
<string name="revanced_spoof_video_streams_about_android_title">Android āĻ¸ā§āĻĒ⧁āĻĢāĻŋāĻ‚āϝāĻŧ⧇āϰ āĻĒāĻžāĻ°ā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž</string> <string name="revanced_spoof_video_streams_about_android_title">Android āĻ¸ā§āĻĒ⧁āĻĢāĻŋāĻ‚āϝāĻŧ⧇āϰ āĻĒāĻžāĻ°ā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āύ⧇āχ <string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āĻ…āύ⧁āĻĒāĻ¸ā§āĻĨāĻŋāϤ
â€ĸ āĻ¸ā§āĻĨāĻŋāϰ āĻ­āϞāĻŋāωāĻŽ āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž â€ĸ āĻ¸ā§āĻĨāĻŋāϤāĻŋāĻļā§€āϞ āĻ­āϞāĻŋāωāĻŽ āωāĻĒāϞāĻŦā§āϧ āύ⧇āχ"</string>
â€ĸ āĻŽā§‚āϞ āĻ…āĻĄāĻŋāĻ“ āĻœā§‹āϰ āĻ•āϰ⧇ āϚāĻžāϞ⧁ āĻ•āϰāĻž āϝāĻžāϝāĻŧ āύāĻž"</string> <string name="revanced_spoof_video_streams_about_ipados_summary">â€ĸ āĻ­āĻŋāĻĄāĻŋāĻ“ ā§§:ā§Ļā§Ļ āĻŽāĻŋāύāĻŋāĻŸā§‡ āĻŦāĻ¨ā§āϧ āĻšāϤ⧇ āĻĒāĻžāϰ⧇, āĻ…āĻĨāĻŦāĻž āĻ•āĻŋāϛ⧁ āĻ…āĻžā§āϚāϞ⧇ āωāĻĒāϞāĻŦā§āϧ āύāĻžāĻ“ āĻšāϤ⧇ āĻĒāĻžāϰ⧇</string>
<string name="revanced_spoof_video_streams_about_experimental">â€ĸ āĻĒāϰ⧀āĻ•ā§āώāĻžāĻŽā§‚āϞāĻ• āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āĻāĻŦāĻ‚ āϝ⧇āϕ⧋āύ⧋ āϏāĻŽāϝāĻŧ āĻ•āĻžāϜ āĻ•āϰāĻž āĻŦāĻ¨ā§āϧ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇</string>
<string name="revanced_spoof_video_streams_about_no_av1">â€ĸ āϕ⧋āύ⧋ AV1 āĻ­āĻŋāĻĄāĻŋāĻ“ āϕ⧋āĻĄā§‡āĻ• āύ⧇āχ</string> <string name="revanced_spoof_video_streams_about_no_av1">â€ĸ āϕ⧋āύ⧋ AV1 āĻ­āĻŋāĻĄāĻŋāĻ“ āϕ⧋āĻĄā§‡āĻ• āύ⧇āχ</string>
<string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ āϞāĻ—āφāωāϟ āĻ•āϰāĻž āĻšāϞ⧇ āĻŦāĻž āĻ›āĻĻā§āĻŽāĻŦ⧇āĻļā§€ āĻŽā§‹āĻĄā§‡ āĻŦāĻžāĻšā§āϚāĻžāĻĻ⧇āϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāϞāϤ⧇ āύāĻžāĻ“ āĻĒāĻžāϰ⧇</string> <string name="revanced_spoof_video_streams_about_kids_videos">â€ĸ āϞāĻ—āφāωāϟ āĻ•āϰāĻž āĻšāϞ⧇ āĻŦāĻž āĻ›āĻĻā§āĻŽāĻŦ⧇āĻļā§€ āĻŽā§‹āĻĄā§‡ āĻŦāĻžāĻšā§āϚāĻžāĻĻ⧇āϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāϞāϤ⧇ āύāĻžāĻ“ āĻĒāĻžāϰ⧇</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻĻ⧇āĻ–āĻžāύ</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_title">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻĻ⧇āĻ–āĻžāύ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āĻĒā§āϰāĻ•āĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāĻŦ⧇</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āĻĒā§āϰāĻ•āĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāĻŦ⧇</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āϞ⧁āĻ•āĻžāύ⧋ āĻšāĻŦ⧇</string> <string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āϞ⧁āĻ•āĻžāύ⧋ āĻšāĻŦ⧇</string>
<string name="revanced_spoof_video_streams_language_title">VR āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ…āĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ­āĻžāώāĻž</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>
</patch>
</app>
<app id="music">
<patch id="misc.settings.settingsPatch">
<string name="revanced_settings_music_screen_0_about_title">āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇</string>
<string name="revanced_settings_music_screen_1_ads_title">āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāύ</string>
<string name="revanced_settings_music_screen_2_general_title">āϏāĻžāϧāĻžāϰāĻŖ</string>
<string name="revanced_settings_music_screen_3_player_title">āĻĒā§āϞ⧇āϝāĻŧāĻžāϰ</string>
<string name="revanced_settings_music_screen_4_misc_title">āĻŦāĻŋāĻŦāĻŋāϧ</string>
</patch>
<patch id="ad.video.hideVideoAdsPatch">
<string name="revanced_music_hide_video_ads_title">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāύ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_music_hide_video_ads_summary_on">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāύ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_music_hide_video_ads_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāύ āĻĻ⧇āĻ–āĻžāύ⧋ āφāϛ⧇</string>
</patch>
<patch id="interaction.permanentrepeat.permanentRepeatPatch">
<string name="revanced_music_play_permanent_repeat_title">āĻ¸ā§āĻĨāĻžāϝāĻŧā§€ āĻĒ⧁āύāϰāĻžāĻŦ⧃āĻ¤ā§āϤāĻŋ āϏāĻ•ā§āώāĻŽ āĻ•āϰ⧁āύ</string>
<string name="revanced_music_play_permanent_repeat_summary_on">āĻ¸ā§āĻĨāĻžāϝāĻŧā§€ āĻĒ⧁āύāϰāĻžāĻŦ⧃āĻ¤ā§āϤāĻŋ āϏāĻ•ā§āώāĻŽ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_music_play_permanent_repeat_summary_off">āĻ¸ā§āĻĨāĻžāϝāĻŧā§€ āĻĒ⧁āύāϰāĻžāĻŦ⧃āĻ¤ā§āϤāĻŋ āĻ…āĻ•ā§āώāĻŽ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
</patch>
<patch id="layout.compactheader.hideCategoryBar">
<string name="revanced_music_hide_category_bar_title">āĻ•ā§āϝāĻžāϟāĻžāĻ—āϰāĻŋ āĻŦāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_music_hide_category_bar_summary_on">āĻ•ā§āϝāĻžāϟāĻžāĻ—āϰāĻŋ āĻŦāĻžāϰ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_music_hide_category_bar_summary_off">āĻ•ā§āϝāĻžāϟāĻžāĻ—āϰāĻŋ āĻŦāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āφāϛ⧇</string>
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title">\'āϗ⧇āϟ āĻŽāĻŋāωāϜāĻŋāĻ• āĻĒā§āϰāĻŋāĻŽāĻŋāϝāĻŧāĻžāĻŽ\' āϞ⧇āĻŦ⧇āϞ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_music_hide_get_premium_label_summary_on">āϞ⧇āĻŦ⧇āϞ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_music_hide_get_premium_label_summary_off">āϞ⧇āĻŦ⧇āϞ āĻĻ⧇āĻ–āĻžāύ⧋ āφāϛ⧇</string>
</patch>
<patch id="layout.upgradebutton.hideUpgradeButtonPatch">
<string name="revanced_music_hide_upgrade_button_title">āφāĻĒāĻ—ā§āϰ⧇āĻĄ āĻŦāĻžāϟāύ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_music_hide_upgrade_button_summary_on">āĻŦāĻžāϟāύ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_music_hide_upgrade_button_summary_off">āĻŦāĻžāϟāύ āĻĻ⧇āĻ–āĻžāύ⧋ āφāϛ⧇</string>
</patch> </patch>
</app> </app>
<app id="twitch"> <app id="twitch">

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