Compare commits

..

59 Commits

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

### Bug Fixes

* **Instagram - Limit feed to followed profiles:** Change patch to default off ([767f1e3](767f1e3695))
2025-09-19 15:43:08 +00:00
LisoUseInAIKyrios
767f1e3695 fix(Instagram - Limit feed to followed profiles): Change patch to default off
Co-authored-by: brosssh <44944126+brosssh@users.noreply.github.com>
2025-09-19 19:40:32 +04:00
github-actions[bot]
7857876551 chore: Sync translations (#5933) 2025-09-19 19:40:03 +04:00
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 6551 additions and 2718 deletions

View File

@@ -1,3 +1,191 @@
# [5.40.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.40.0-dev.2...v5.40.0-dev.3) (2025-09-19)
### Bug Fixes
* **Instagram - Limit feed to followed profiles:** Change patch to default off ([767f1e3](https://github.com/ReVanced/revanced-patches/commit/767f1e3695327bdbc4daea8b50a80d4c0a38456a))
# [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)

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

View File

@@ -1,6 +1,4 @@
package app.revanced.extension.youtube;
import androidx.annotation.NonNull;
package app.revanced.extension.shared;
/**
* 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);
}
}

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 java.util.ArrayList;
@@ -57,11 +56,13 @@ public abstract class TrieSearch<T> {
if (searchTextLength - searchTextIndex < patternLength - patternStartIndex) {
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++) {
if (enclosingNode.getCharValue(searchText, i) != enclosingNode.getCharValue(pattern, j)) {
return false;
}
}
return callback == null || callback.patternMatched(searchText,
searchTextIndex - patternStartIndex, patternLength, callbackParameter);
}
@@ -136,7 +137,7 @@ public abstract class TrieSearch<T> {
* @param patternLength Length of the pattern.
* @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) {
if (patternIndex == patternLength) { // Reached the end of the pattern.
if (endOfPatternCallback == null) {
@@ -145,6 +146,7 @@ public abstract class TrieSearch<T> {
endOfPatternCallback.add(callback);
return;
}
if (leaf != null) {
// Reached end of the graph and a leaf exist.
// 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);
return;
}
final char character = getCharValue(pattern, patternIndex);
final int arrayIndex = hashIndexForTableSize(children.length, character);
TrieNode<T> child = children[arrayIndex];
@@ -183,6 +186,7 @@ public abstract class TrieSearch<T> {
//noinspection unchecked
TrieNode<T>[] replacement = new TrieNode[replacementArraySize];
addNodeToArray(replacement, child);
boolean collision = false;
for (TrieNode<T> existingChild : children) {
if (existingChild != null) {
@@ -195,6 +199,7 @@ public abstract class TrieSearch<T> {
if (collision) {
continue;
}
children = replacement;
return;
}
@@ -234,6 +239,7 @@ public abstract class TrieSearch<T> {
if (leaf != null && leaf.matches(startNode, searchText, searchTextEndIndex, searchTextIndex, callbackParameter)) {
return true; // Leaf exists and it matched the search text.
}
List<TriePatternMatchedCallback<T>> endOfPatternCallback = node.endOfPatternCallback;
if (endOfPatternCallback != null) {
final int matchStartIndex = searchTextIndex - currentMatchLength;
@@ -246,6 +252,7 @@ public abstract class TrieSearch<T> {
}
}
}
TrieNode<T>[] children = node.children;
if (children == null) {
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) {
numberOfPointers += 4; // Number of fields in leaf node.
}
if (endOfPatternCallback != null) {
numberOfPointers += endOfPatternCallback.size();
}
if (children != null) {
numberOfPointers += children.length;
for (TrieNode<T> child : children) {
@@ -308,13 +317,13 @@ public abstract class TrieSearch<T> {
private final List<T> patterns = new ArrayList<>();
@SafeVarargs
TrieSearch(@NonNull TrieNode<T> root, @NonNull T... patterns) {
TrieSearch(TrieNode<T> root, T... patterns) {
this.root = Objects.requireNonNull(root);
addPatterns(patterns);
}
@SafeVarargs
public final void addPatterns(@NonNull T... patterns) {
public final void addPatterns(T... patterns) {
for (T pattern : patterns) {
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.
*/
public void addPattern(@NonNull T pattern) {
public void addPattern(T pattern) {
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 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));
}
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
patterns.add(pattern);
root.addPattern(pattern, 0, patternLength, callback);
}
public final boolean matches(@NonNull T textToSearch) {
public final boolean matches(T textToSearch) {
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),
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));
}
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);
}
@@ -370,11 +379,11 @@ public abstract class TrieSearch<T> {
* @param callbackParameter Optional parameter passed to the callbacks.
* @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);
}
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) {
if (endIndex > textToSearchLength) {
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 app.revanced.extension.shared.settings.Setting.parent;
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.
@@ -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 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_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.util.AttributeSet;
import android.preference.Preference;
import app.revanced.extension.shared.settings.preference.LogBufferManager;
/**
* 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.util.AttributeSet;
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.

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 androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.Locale;
import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.BaseSettings;
@SuppressWarnings("ConstantLocale")
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
ANDROID_VR_NO_AUTH(
ANDROID_VR_1_61_48(
28,
"ANDROID_VR",
"com.google.android.apps.youtube.vr.oculus",
@@ -26,30 +31,31 @@ public enum ClientType {
"132.0.6808.3",
"1.61.48",
false,
false,
"Android VR No auth"
"Android VR 1.61"
),
// Chromecast with Google TV 4K.
// https://dumps.tadiphone.dev/dumps/google/kirkwood
ANDROID_UNPLUGGED(
29,
"ANDROID_UNPLUGGED",
"com.google.android.apps.youtube.unplugged",
"Google",
"Google TV Streamer",
"Android",
"14",
"34",
"UTT3.240625.001.K5",
"132.0.6808.3",
"8.49.0",
true,
true,
"Android TV"
/**
* Uses non adaptive bitrate, which fixes audio stuttering with YT Music.
* Does not use AV1.
*/
ANDROID_VR_1_43_32(
ANDROID_VR_1_61_48.id,
ANDROID_VR_1_61_48.clientName,
Objects.requireNonNull(ANDROID_VR_1_61_48.packageName),
ANDROID_VR_1_61_48.deviceMake,
ANDROID_VR_1_61_48.deviceModel,
ANDROID_VR_1_61_48.osName,
ANDROID_VR_1_61_48.osVersion,
Objects.requireNonNull(ANDROID_VR_1_61_48.androidSdkVersion),
Objects.requireNonNull(ANDROID_VR_1_61_48.buildId),
"107.0.5284.2",
"1.43.32",
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
// https://dumps.tadiphone.dev/dumps/google/barbet
/**
* Cannot play livestreams and lacks HDR, but can play videos with music and labeled "for children".
* <a href="https://dumps.tadiphone.dev/dumps/google/barbet">Google Pixel 9 Pro Fold</a>
*/
ANDROID_CREATOR(
14,
"ANDROID_CREATOR",
@@ -63,45 +69,47 @@ public enum ClientType {
"132.0.6779.0",
"23.47.101",
true,
true,
"Android Creator"
"Android Studio"
),
IOS_UNPLUGGED(
33,
"IOS_UNPLUGGED",
"com.google.ios.youtubeunplugged",
/**
* Internal YT client for an unreleased YT client. May stop working at any time.
*/
VISIONOS(101,
"VISIONOS",
"Apple",
forceAVC()
// 11 Pro Max (last device with iOS 13)
? "iPhone12,5"
// 15 Pro Max
: "iPhone16,2",
"iOS",
forceAVC()
// iOS 13 and earlier uses only AVC. 14+ adds VP9 and AV1.
? "13.7.17H35"
: "18.2.22C152",
null,
null,
null,
// Version number should be a valid iOS release.
// https://www.ipa4fun.com/history/152043/
forceAVC()
// Some newer versions can also force AVC,
// but 6.45 is the last version that supports iOS 13.
? "6.45"
: "8.49",
true,
true,
forceAVC()
? "iOS TV Force AVC"
: "iOS TV"
"RealityDevice14,1",
"visionOS",
"1.3.21O771",
"0.1",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
false,
"visionOS"
),
/**
* The device machine id for the iPad 6th Gen (iPad7,6).
* AV1 hardware decoding is not supported.
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
*
* Based on Google's actions to date, PoToken may not be required on devices with very low specs.
* For example, suppose the User-Agent for a PlayStation 3 (with 256MB of RAM) is used.
* Accessing 'Web' (https://www.youtube.com) will redirect to 'TV' (https://www.youtube.com/tv).
* 'TV' target devices with very low specs, such as embedded devices, game consoles, and blu-ray players, so PoToken is not required.
*
* For this reason, the device machine id for the iPad 6th Gen (with 2GB of RAM),
* the lowest spec device capable of running iPadOS 17, was used.
*/
IPADOS(5,
"IOS",
"Apple",
"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
* <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.
*/
@Nullable
private final String packageName;
/**
@@ -166,12 +175,6 @@ public enum ClientType {
*/
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.
*/
@@ -182,19 +185,20 @@ public enum ClientType {
*/
public final String friendlyName;
@SuppressWarnings("ConstantLocale")
/**
* Android constructor.
*/
ClientType(int id,
String clientName,
String packageName,
@NonNull String packageName,
String deviceMake,
String deviceModel,
String osName,
String osVersion,
@Nullable String androidSdkVersion,
@Nullable String buildId,
@Nullable String cronetVersion,
@NonNull String androidSdkVersion,
@NonNull String buildId,
@NonNull String cronetVersion,
String clientVersion,
boolean requiresAuth,
boolean useAuth,
String friendlyName) {
this.id = id;
@@ -208,36 +212,46 @@ public enum ClientType {
this.buildId = buildId;
this.cronetVersion = cronetVersion;
this.clientVersion = clientVersion;
this.requiresAuth = requiresAuth;
this.useAuth = useAuth;
this.friendlyName = friendlyName;
Locale defaultLocale = Locale.getDefault();
if (androidSdkVersion == null) {
// Convert version from '18.2.22C152' into '18_2_22'
String userAgentOsVersion = osVersion
.replaceAll("(\\d+\\.\\d+\\.\\d+).*", "$1")
.replace(".", "_");
// https://github.com/mitmproxy/mitmproxy/issues/4836
this.userAgent = String.format("%s/%s (%s; U; CPU iOS %s like Mac OS X; %s)",
packageName,
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)
);
}
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);
}
@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 java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
@SuppressWarnings("unused")
public class SpoofVideoStreamsPatch {
/**
* 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 FIX_HLS_CURRENT_TIME = SPOOF_STREAMING_DATA
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED;
@Nullable
private static volatile AppLanguage languageOverride;
/**
* 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);
private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_61_48;
/**
* @return If this patch was included during patching.
*/
private static boolean isPatchIncluded() {
public static boolean isPatchIncluded() {
return false; // Modified during patching.
}
public static boolean notSpoofingToAndroid() {
return !isPatchIncluded()
|| !BaseSettings.SPOOF_VIDEO_STREAMS.get()
|| BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED;
@Nullable
public static AppLanguage getLanguageOverride() {
return languageOverride;
}
/**
* @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();
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) {
Logger.printException(() -> "blockGetWatchRequest failure", ex);
@@ -77,9 +109,9 @@ public class SpoofVideoStreamsPatch {
String path = originalUri.getPath();
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) {
Logger.printException(() -> "blockInitPlaybackRequest failure", ex);
@@ -252,16 +284,7 @@ public class SpoofVideoStreamsPatch {
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {
return BaseSettings.SPOOF_VIDEO_STREAMS.get()
&& 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;
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
}
}
}

View File

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

View File

@@ -1,5 +1,6 @@
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 androidx.annotation.NonNull;
@@ -13,12 +14,18 @@ import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
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.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
@@ -35,21 +42,27 @@ import app.revanced.extension.shared.spoof.ClientType;
*/
public class StreamingDataRequest {
private static final ClientType[] CLIENT_ORDER_TO_USE;
private static volatile ClientType[] clientOrderToUse = ClientType.values();
static {
ClientType[] allClientTypes = ClientType.values();
ClientType preferredClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
public static void setClientOrderToUse(List<ClientType> availableClients, ClientType preferredClient) {
Objects.requireNonNull(preferredClient);
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
CLIENT_ORDER_TO_USE[0] = preferredClient;
int availableClientSize = availableClients.size();
if (!availableClients.contains(preferredClient)) {
availableClientSize++;
}
clientOrderToUse = new ClientType[availableClientSize];
clientOrderToUse[0] = preferredClient;
int i = 1;
for (ClientType c : allClientTypes) {
for (ClientType c : availableClients) {
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";
@@ -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;
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
+ " videoId: " + videoId);
return null;
@@ -193,9 +216,9 @@ public class StreamingDataRequest {
// Retry with different client if empty response body is received.
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.
final boolean showErrorToast = (++i == CLIENT_ORDER_TO_USE.length) || debugEnabled;
final boolean showErrorToast = (++i == clientOrderToUse.length) || debugEnabled;
HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast);
if (connection != null) {
@@ -215,9 +238,13 @@ public class StreamingDataRequest {
while ((bytesRead = inputStream.read(buffer)) >= 0) {
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) {

View File

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

View File

@@ -10,7 +10,7 @@ import java.util.List;
import app.revanced.extension.shared.Logger;
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;
@SuppressWarnings("unused")

View File

@@ -74,6 +74,10 @@ final class ButtonsFilter extends Filter {
Settings.HIDE_ASK_BUTTON,
"yt_fill_spark"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHOP_BUTTON,
"yt_outline_bag"
),
new ByteArrayFilterGroup(
Settings.HIDE_STOP_ADS_BUTTON,
"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.Utils;
import app.revanced.extension.youtube.ByteTrieSearch;
import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.youtube.settings.Settings;
/**

View File

@@ -1,6 +1,6 @@
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.shared.PlayerType;

View File

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

View File

@@ -5,9 +5,9 @@ import androidx.annotation.NonNull;
import java.util.*;
import java.util.function.Consumer;
import app.revanced.extension.youtube.ByteTrieSearch;
import app.revanced.extension.youtube.StringTrieSearch;
import app.revanced.extension.youtube.TrieSearch;
import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.shared.TrieSearch;
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.Utils;
import app.revanced.extension.youtube.ByteTrieSearch;
import app.revanced.extension.youtube.StringTrieSearch;
import app.revanced.extension.youtube.TrieSearch;
import app.revanced.extension.shared.ByteTrieSearch;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.shared.TrieSearch;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar;
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.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.settings.Settings;
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.settings.BaseSettings;
import app.revanced.extension.youtube.StringTrieSearch;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")

View File

@@ -9,13 +9,13 @@ import app.revanced.extension.youtube.shared.ShortsPlayerState;
public class PlayerFlyoutMenuItemsFilter extends Filter {
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
public boolean isAvailable() {
// Check conditions of launch and now. Otherwise if spoofing is changed
// 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.settings.Settings;
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.

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;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceFragment;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.TextView;
import android.view.View;
import android.widget.Toolbar;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.settings.BaseActivityHook;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
/**
* Hooks LicenseActivity.
* <p>
* This class is responsible for injecting our own fragment by replacing the LicenseActivity.
* Hooks LicenseActivity to inject a custom ReVancedPreferenceFragment with a toolbar and search functionality.
*/
@SuppressWarnings("unused")
public class LicenseActivityHook extends Activity {
@SuppressWarnings("deprecation")
public class LicenseActivityHook extends BaseActivityHook {
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")
public static SearchViewController searchViewController;
public static void setToolbarLayoutParams(Toolbar toolbar) {
if (toolbarLayoutParams != null) {
toolbar.setLayoutParams(toolbarLayoutParams);
/**
* Injection point
* <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.
* Overrides the ReVanced settings language.
*/
@SuppressWarnings("unused")
public static Context getAttachBaseContext(Context original) {
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
if (language == AppLanguage.DEFAULT) {
@@ -57,6 +127,7 @@ public class LicenseActivityHook extends Activity {
/**
* Injection point.
*/
@SuppressWarnings("unused")
public static boolean useCairoSettingsFragment(boolean original) {
// Early targets have layout issues and it's better to always force off.
if (!VersionCheckPatch.IS_19_34_OR_GREATER) {
@@ -80,87 +151,6 @@ public class LicenseActivityHook extends Activity {
/**
* Injection point.
* <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
* 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) {
if (searchViewController != null) {
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.StartPage;
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.MiniplayerType;
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.StringSetting;
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
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);
// 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
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_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_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_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 SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
"revanced_spoof_device_dimensions_user_dialog_message");
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS));
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
"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.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"})
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.
String summary = str("revanced_force_original_audio_not_available");
setSummary(summary);
setSummaryOn(summary);
setSummaryOff(summary);
super.setSummary(summary);
super.setSummaryOn(summary);
super.setSummaryOff(summary);
super.setEnabled(false);
}
}
@@ -33,4 +41,23 @@ public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
public ForceOriginalAudioSwitchPreference(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

@@ -12,8 +12,8 @@ import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
public class HideAudioFlyoutMenuPreference extends SwitchPreference {
{
// Audio menu is not available if spoofing to Android client type.
if (!SpoofVideoStreamsPatch.notSpoofingToAndroid()) {
// Audio menu is not available if spoofing to most client types.
if (SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
String summary = str("revanced_hide_player_flyout_audio_track_not_available");
setSummary(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.Utils.getResourceIdentifier;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.graphics.Insets;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
@@ -17,11 +13,6 @@ import android.preference.SwitchPreference;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
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 androidx.annotation.CallSuper;
@@ -40,16 +31,16 @@ import java.util.regex.Pattern;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
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.ToolbarPreferenceFragment;
import app.revanced.extension.youtube.settings.LicenseActivityHook;
import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockPreferenceGroup;
/**
* Preference fragment for ReVanced settings.
*/
@SuppressWarnings("deprecation")
public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
@SuppressWarnings({"deprecation", "NewApi"})
public class ReVancedPreferenceFragment extends ToolbarPreferenceFragment {
/**
* 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<>();
@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.
*/
@@ -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.
*
* @param includeDepth Menu depth to start including preferences.
* A value of 0 adds all preferences.
*/
@@ -222,75 +208,6 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
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")

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.Setting;
import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings({"deprecation", "unused"})
public class SpoofStreamingDataSideEffectsPreference extends Preference {
@@ -69,7 +70,7 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
}
private void updateUI() {
ClientType clientType = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
ClientType clientType = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
if (currentClientType == clientType) {
return;
}
@@ -78,21 +79,25 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
Logger.printDebug(() -> "Updating spoof stream side effects preference");
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());
String key = "revanced_spoof_video_streams_about_" +
(clientType == ClientType.IOS_UNPLUGGED
? "ios_tv"
: "android");
String title = str(key + "_title");
String summary = str(key + "_summary");
setTitle(str("revanced_spoof_video_streams_about_title"));
// Android VR supports AV1 but all other clients do not.
if (clientType != ClientType.ANDROID_VR_NO_AUTH) {
String summary = str(clientType == ClientType.IPADOS
? "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");
} 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);
}
}

View File

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

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 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 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 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 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 final class app/revanced/patches/music/layout/upgradebutton/RemoveUpgradeButtonPatchKt {
public static final fun getRemoveUpgradeButtonPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
public final class app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatchKt {
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 {
@@ -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 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;
}
@@ -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 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 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,64 @@
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.",
use = false
) {
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,
// Injection Jump
Opcode.ADD_INT_LIT8, //Increase Index
Opcode.GOTO_16 // Jump to loopStart
Opcode.GOTO // Jump to loopStart
// LoopEnd
)
}

View File

@@ -15,7 +15,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
description = "Hides navigation bar buttons, such as the Reels and Create button.",
use = false
) {
compatibleWith("com.instagram.android")
compatibleWith("com.instagram.android"("397.1.0.52.81"))
val hideReels by booleanOption(
key = "hideReels",
@@ -49,7 +49,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
val freeRegister = findFreeRegister(insertIndex, loopIndexRegister)
val instruction = getInstruction(endIndex - 1)
var instructions = buildString {
val instructions = buildString {
if (hideCreate!!) {
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
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
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")
val hideVideoAdsPatch = bytecodePatch(
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(
"com.google.android.apps.youtube.music"(
"7.29.52"
@@ -15,9 +29,21 @@ val hideVideoAdsPatch = bytecodePatch(
)
execute {
addResources("music", "ad.video.hideVideoAdsPatch")
PreferenceScreen.ADS.addPreferences(
SwitchPreference("revanced_music_hide_video_ads"),
)
navigate(showVideoAdsParentFingerprint.originalMethod)
.to(showVideoAdsParentFingerprint.patternMatch!!.startIndex + 1)
.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
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
@Suppress("unused")
@@ -8,6 +10,11 @@ val enableExclusiveAudioPlaybackPatch = bytecodePatch(
name = "Enable exclusive audio playback",
description = "Enables the option to play audio without video.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"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.patch.bytecodePatch
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")
val permanentRepeatPatch = bytecodePatch(
name = "Permanent repeat",
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.",
use = false,
description = "Adds an option to always repeat even if the playlist ends or another track is played."
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
@@ -18,13 +32,27 @@ val permanentRepeatPatch = bytecodePatch(
)
execute {
addResources("music", "interaction.permanentrepeat.permanentRepeatPatch")
PreferenceScreen.PLAYER.addPreferences(
SwitchPreference("revanced_music_play_permanent_repeat"),
)
val startIndex = repeatTrackFingerprint.patternMatch!!.endIndex
val repeatIndex = startIndex + 1
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(
startIndex,
"goto :repeat",
"""
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->permanentRepeat()Z
move-result v$freeRegister
if-nez v$freeRegister, :repeat
""",
ExternalLabel("repeat", instructions[repeatIndex]),
)
}

View File

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

View File

@@ -1,16 +1,31 @@
package app.revanced.patches.music.layout.premium
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.replaceInstruction
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
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideGetPremiumPatch;"
@Suppress("unused")
val hideGetPremiumPatch = bytecodePatch(
name = "Hide 'Get Music Premium' label",
description = "Hides the \"Get Music Premium\" label from the account menu and settings.",
name = "Hide 'Get Music Premium'",
description = "Adds an option to hide the \"Get Music Premium\" label in the settings and account menu.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
@@ -18,6 +33,12 @@ val hideGetPremiumPatch = bytecodePatch(
)
execute {
addResources("music", "layout.premium.hideGetPremiumPatch")
PreferenceScreen.ADS.addPreferences(
SwitchPreference("revanced_music_hide_get_premium_label"),
)
hideGetPremiumFingerprint.method.apply {
val insertIndex = hideGetPremiumFingerprint.patternMatch!!.endIndex
@@ -37,12 +58,17 @@ val hideGetPremiumPatch = bytecodePatch(
)
}
membershipSettingsFingerprint.method.addInstructions(
membershipSettingsFingerprint.method.addInstructionsWithLabels(
0,
"""
const/4 v0, 0x0
return-object v0
""",
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideGetPremiumLabel()Z
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.patch.bytecodePatch
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 com.android.tools.smali.dexlib2.Opcode
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.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;"
@Suppress("unused")
val removeUpgradeButtonPatch = bytecodePatch(
name = "Remove upgrade button",
description = "Removes the upgrade tab from the pivot bar.",
val hideUpgradeButton = bytecodePatch(
name = "Hide upgrade button",
description = "Hides the upgrade tab from the pivot bar.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
@@ -25,6 +39,15 @@ val removeUpgradeButtonPatch = bytecodePatch(
)
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 {
val pivotBarElementFieldReference =
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
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
@Suppress("unused")
@@ -8,6 +10,11 @@ val bypassCertificateChecksPatch = bytecodePatch(
name = "Bypass certificate checks",
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"

View File

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

View File

@@ -1,12 +1,17 @@
package app.revanced.patches.music.misc.gms
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.gms.Constants.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.shared.castContextFetchFingerprint
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.primeMethodFingerprint
@Suppress("unused")
@@ -33,4 +38,23 @@ private fun gmsCoreSupportResourcePatch(
toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
gmsCoreVendorGroupIdOption = gmsCoreVendorGroupIdOption,
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 {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("Z")
parameters()
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.bytecodePatch
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.music.misc.extension.sharedExtensionPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
@@ -46,6 +46,8 @@ fun spoofVideoStreamsPatch(
dependsOn(addResourcesPatch)
execute {
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
// region Enable extension helper method used by other patches
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)

View File

@@ -187,11 +187,16 @@ val customThemePatch = resourcePatch(
}
// Login screen gradient.
document("res/drawable/start_screen_gradient.xml").use { document ->
val gradientNode = document.getElementsByTagName("gradient").item(0) as Element
try {
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:endColor", "@color/gray_7")
gradientNode.setAttribute("android:startColor", "@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;"
@Deprecated("Patch no longer functions")
@Suppress("unused")
val spoofClientPatch = bytecodePatch(
name = "Spoof client",
description = "Spoofs the client to fix various functions of the app.",
) {
val requestListenerPort by intOption(

View File

@@ -2,12 +2,6 @@ package app.revanced.patches.viber.ads
import app.revanced.patcher.fingerprint
internal val adsFreeFingerprint = fingerprint {
returns("I")
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
}
internal val findAdStringFingerprint = fingerprint {
strings("viber_plus_debug_ads_free_flag")
}

View File

@@ -1,17 +1,41 @@
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.util.indexOfFirstInstructionReversedOrThrow
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")
val hideAdsPatch = bytecodePatch(
name = "Hide Ads",
description = "Hides ad banners between chats.",
) {
compatibleWith("com.viber.voip")
compatibleWith("com.viber.voip"("25.9.2.0", "26.1.2.0"))
execute {
// Return 1 (true) indicating ads should be disabled.
adsFreeFingerprint.method.returnEarly(1)
val method = findAdStringFingerprint.method
// 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.
mainActivityOnCreateFingerprint.method.addInstruction(
1,
0,
"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_save_button"),
SwitchPreference("revanced_hide_share_button"),
SwitchPreference("revanced_hide_shop_button"),
SwitchPreference("revanced_hide_stop_ads_button"),
SwitchPreference("revanced_hide_thanks_button"),
)

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.seekbar
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.getReference
import app.revanced.util.indexOfFirstInstruction
@@ -103,7 +104,7 @@ internal val launchScreenLayoutTypeFingerprint = fingerprint {
custom { method, _ ->
val firstParameter = method.parameterTypes.firstOrNull()
// 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+
&& method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag)
}

View File

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

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.theme
import app.revanced.patcher.fingerprint
import app.revanced.patches.youtube.shared.YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -37,6 +38,6 @@ internal val splashScreenStyleFingerprint = fingerprint {
parameters("Landroid/os/Bundle;")
literal { SPLASH_SCREEN_STYLE_FEATURE_FLAG }
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(
// Insert index must be greater than the insert index used by GmsCoreSupport,
// as both patch the same method and GmsCore check should be first.
1,
0,
"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 =
"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(
name = "Enable debugging",
description = "Adds options for debugging and exporting ReVanced logs to the clipboard.",
@@ -45,6 +47,7 @@ val enableDebuggingPatch = bytecodePatch(
)
execute {
addResources("shared", "misc.debugging.enableDebuggingPatch")
addResources("youtube", "misc.debugging.enableDebuggingPatch")
PreferenceScreen.MISC.addPreferences(
@@ -58,13 +61,13 @@ val enableDebuggingPatch = bytecodePatch(
SwitchPreference("revanced_debug_toast_on_error"),
NonInteractivePreference(
"revanced_debug_export_logs_to_clipboard",
tag = "app.revanced.extension.youtube.settings.preference.ExportLogToClipboardPreference",
selectable = true,
tag = "app.revanced.extension.shared.settings.preference.ExportLogToClipboardPreference",
selectable = true
),
NonInteractivePreference(
"revanced_debug_logs_clear_buffer",
tag = "app.revanced.extension.youtube.settings.preference.ClearLogBufferPreference",
selectable = true,
tag = "app.revanced.extension.shared.settings.preference.ClearLogBufferPreference",
selectable = true
),
),
),

View File

@@ -34,12 +34,7 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
addResources("youtube", "misc.dns.checkWatchHistoryDomainNameResolutionPatch")
mainActivityOnCreateFingerprint.method.addInstruction(
// FIXME: Insert index must be greater than the insert index used by GmsCoreSupport,
// 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,
0,
"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.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
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).
*/
// Extension context is the Activity itself.
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")
}
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,
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
executeBlock = {
addResources("youtube", "misc.gms.gmsCoreSupportResourcePatch")
addResources("shared", "misc.gms.gmsCoreSupportResourcePatch")
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
@@ -62,10 +62,14 @@ private fun gmsCoreSupportResourcePatch(
"microg_settings",
intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") {
"$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.
mainActivityOnBackPressedFingerprint.method.addInstruction(
0,
"invoke-static { p0 }, " +
"$EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V",
"invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->onBackPressed(Landroid/app/Activity;)V",
)
// 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.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;"
internal var appearanceStringId = -1L
@@ -37,10 +39,6 @@ internal var appearanceStringId = -1L
private val preferences = mutableSetOf<BasePreference>()
fun addSettingPreference(screen: BasePreference) {
preferences += screen
}
private val settingsResourcePatch = resourcePatch {
dependsOn(
resourceMappingPatch,
@@ -225,7 +223,9 @@ val settingsPatch = bytecodePatch(
licenseActivityOnCreateFingerprint.method.addInstructions(
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
"""
)
@@ -249,7 +249,7 @@ val settingsPatch = bytecodePatch(
).toMutable().apply {
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
invoke-super { p0, p1 }, $superclass->attachBaseContext(Landroid/content/Context;)V
return-void
@@ -294,7 +294,7 @@ val settingsPatch = bytecodePatch(
addInstructions(
"""
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
"""
)
@@ -309,15 +309,15 @@ val settingsPatch = bytecodePatch(
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructionsAtControlFlowLabel(
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(
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
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
@@ -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.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
compatibleWith(
"com.google.android.youtube"(
"19.34.42",
"19.43.41",
"19.47.53",
"20.07.39",
"20.12.46",
"20.13.41",
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;"
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
block = {
compatibleWith(
"com.google.android.youtube"(
"19.34.42",
"19.43.41",
"19.47.53",
"20.07.39",
"20.12.46",
"20.13.41",
)
)
)
dependsOn(
userAgentClientSpoofPatch,
settingsPatch,
versionCheckPatch
)
}, {
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
}, {
is_20_03_or_greater
}, {
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
dependsOn(
userAgentClientSpoofPatch,
settingsPatch,
versionCheckPatch
)
},
fixMediaFetchHotConfigChanges = {
is_19_34_or_greater
},
fixMediaFetchHotConfigAlternativeChanges = {
// In 20.14 the flag was merged with 20.03 start playback flag.
is_20_10_or_greater && !is_20_14_or_greater
},
fixParsePlaybackResponseFeatureFlag = {
is_20_03_or_greater
},
executeBlock = {
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
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"),
NonInteractivePreference(
// Requires a key and title but the actual text is chosen at runtime.
key = "revanced_spoof_video_streams_about_android",
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
),
ListPreference(
key = "revanced_spoof_video_streams_language",
// Language strings are declared in Setting patch.
entriesKey = "revanced_language_entries",
entryValuesKey = "revanced_language_entry_values",
tag = "app.revanced.extension.shared.settings.preference.SortedListPreference"
),
SwitchPreference("revanced_spoof_video_streams_ios_force_avc"),
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"),
),
),
)
})
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"),
NonInteractivePreference(
// Requires a key and title but the actual text is chosen at runtime.
key = "revanced_spoof_video_streams_about_android",
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
),
ListPreference(
key = "revanced_spoof_video_streams_language",
// Language strings are declared in Setting patch.
entriesKey = "revanced_language_entries",
entryValuesKey = "revanced_language_entry_values",
tag = "app.revanced.extension.youtube.settings.preference.SpoofAudioSelectorListPreference"
),
SwitchPreference("revanced_spoof_streaming_data_stats_for_nerds"),
)
)
)
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.Opcode
internal const val YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE = "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;"
internal val conversionContextFingerprintToString = fingerprint {
parameters()
strings(
@@ -48,7 +50,7 @@ internal val mainActivityConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters()
custom { _, classDef ->
classDef.endsWith("/MainActivity;")
classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
}
}
@@ -57,7 +59,7 @@ internal val mainActivityOnBackPressedFingerprint = fingerprint {
returns("V")
parameters()
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")
parameters("Landroid/os/Bundle;")
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
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
@@ -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.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.findMethodFromToString
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.insertLiteralOverride
@@ -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
// and instead overrides to the user region language.
if (is_20_07_or_greater) {

View File

@@ -30,6 +30,10 @@ Second \"item\" text"</string>
<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. -->
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
</patch>
</app>
<app id="youtube">
<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.
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. -->
<!-- 'Shop' 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 id="layout.buttons.navigation.navigationButtonsPatch">
@@ -207,8 +212,6 @@ Second \"item\" text"</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
</patch>
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
@@ -240,6 +243,21 @@ Second \"item\" text"</string>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch>
<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>
</app>
<app id="twitch">

View File

@@ -30,6 +30,10 @@ Second \"item\" text"</string>
<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. -->
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
</patch>
</app>
<app id="youtube">
<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.
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. -->
<!-- 'Shop' 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 id="layout.buttons.navigation.navigationButtonsPatch">
@@ -207,8 +212,6 @@ Second \"item\" text"</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
</patch>
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
@@ -240,6 +243,21 @@ Second \"item\" text"</string>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch>
<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>
</app>
<app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. -->
</patch>
<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. -->
<string name="gms_core_toast_not_installed_message">Ų„Ų… ؊ØĒŲ… ØĒØĢØ¨ŲŠØĒ MicroG GmsCore. Ų‚Ų… بØĒØĢØ¨ŲŠØĒŲ‡.</string>
<string name="gms_core_dialog_title">Ø§Ų„ØĨØŦØąØ§ØĄ Ų…ØˇŲ„ŲˆØ¨</string>
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
Ø§Ų†Ų‚Øą ŲŲˆŲ‚ Ø˛Øą Ø§Ų„Ø§ØŗØĒŲ…ØąØ§Øą ŲˆØ§ØŗŲ…Ø­ بØĒØēŲŠŲŠØąØ§ØĒ Ø§Ų„ØĒØ­ØŗŲŠŲ†."</string>
<string name="gms_core_dialog_continue_text">Ų…ØĒابؚ؊</string>
</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 id="youtube">
<patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† ØĒØ´ØēŲŠŲ„ Shorts Ø¨Ø§Ų„ØŽŲ„ŲŲŠØŠ</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_protobuffer_title">ØŗØŦŲ„ Ø¨ØąŲˆØĒŲˆŲƒŲˆŲ„ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</string>
<string name="revanced_debug_protobuffer_summary_on">ØĒØĒØļŲ…Ų† ØŗØŦŲ„Ø§ØĒ Ø§Ų„ØĒØĩØ­ŲŠØ­ Ø§Ų„ØĒØŽØ˛ŲŠŲ† Ø§Ų„Ų…Ø¤Ų‚ØĒ</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>
<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 id="layout.hide.general.hideLayoutComponentsPatch">
<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_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø˛Øą ØĨŲ†Ø´Ø§ØĄ Ų…Ų‚ØˇØš</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. -->
<string name="revanced_hide_save_button_title">ØĨØŽŲØ§ØĄ Ø­ŲØ¸</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_off">؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊</string>
<!-- '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. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ ؁؊ VR</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ ؁؊ Ø§Ų„ŲˆØļØš Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
@@ -1415,10 +1438,6 @@ Second \"item\" text"</string>
ŲŠŲ…ŲƒŲ† ØŖŲ† ŲŠØ¤Ø¯ŲŠ ØĒŲØšŲŠŲ„ Ų‡Ø°Ø§ ØĨŲ„Ų‰ ؁ØĒØ­ ØŦŲˆØ¯ØŠ ØŖØšŲ„Ų‰ Ų„Ų„ŲŲŠØ¯ŲŠŲˆ"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">Ų‚Ø¯ ŲŠØ¤Ø¯ŲŠ ØĒŲ…ŲƒŲŠŲ† Ų‡Ø°Ø§ ØĨŲ„Ų‰ ØĒØ¨Ø§ØˇØ¤ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ ؈ØĒØ¯Ų‡ŲˆØą ØšŲ…Øą Ø§Ų„Ø¨ØˇØ§ØąŲŠØŠ ؈ØĸØĢØ§Øą ØŦØ§Ų†Ø¨ŲŠØŠ ØēŲŠØą Ų…ØšØąŲˆŲØŠ.</string>
</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">
<string name="revanced_disable_haptic_feedback_title">Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</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_off">Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„Øĩ؈ØĒ Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">Ų„Ø§ØŗØĒØŽØ¯Ø§Ų… Ų‡Ø°Ų‡ Ø§Ų„Ų…ŲŠØ˛ØŠØŒ ØēŲŠŲ‘Øą \'Spoof Video Streams\' ØĨŲ„Ų‰ iOS TV</string>
<string name="revanced_force_original_audio_not_available">Ų„Ø§ØŗØĒØŽØ¯Ø§Ų… Ų‡Ø°Ų‡ Ø§Ų„Ų…ŲŠØ˛ØŠØŒ ØēŲŠŲ‘Øą \"ØĒØ˛ŲˆŲŠØą ØĒØ¯ŲŲ‚Ø§ØĒ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ\" ØĨŲ„Ų‰ ØŖŲŠ ØšŲ…ŲŠŲ„ Ø¨Ø§ØŗØĒØĢŲ†Ø§ØĄ Android Studio</string>
</patch>
<patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1532,35 +1551,54 @@ Second \"item\" text"</string>
<string name="revanced_slide_to_seek_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„ØĒŲ…ØąŲŠØą Ų„Ų„ØĒŲ‚Ø¯ŲŠŲ… ØŖŲˆ Ø§Ų„ØĒØąØŦŲŠØš</string>
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_screen_title">Spoof Video Streams</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_title">Ø§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų„ØĒØ˛ŲˆŲŠØą</string>
<string name="revanced_spoof_video_streams_about_android_title">Ø§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų…Ø­Ø§ŲƒØ§ØŠ Ų‡ŲˆŲŠØŠ Android</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…Ų‚ØˇØš Ø§Ų„Øĩ؈ØĒ؊ Ų…ŲŲ‚ŲˆØ¯ØŠ
â€ĸ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØĢابØĒ ØēŲŠØą Ų…ØĒاح
â€ĸ ŲØąØļ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØŖØĩŲ„ŲŠ ØēŲŠØą Ų…ØĒŲˆŲØą"</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ų…ØŗØ§ØąØ§ØĒ Ø§Ų„Øĩ؈ØĒŲŠØŠ Ų…ŲŲ‚ŲˆØ¯ØŠ
â€ĸ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ Ø§Ų„Ų…ØŗØĒŲ‚Øą ØēŲŠØą Ų…ØĒاح"</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_kids_videos">â€ĸ Ų‚Ø¯ Ų„Ø§ ؊ØĒŲ… ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Ø§Ų„Ų…ØŽØĩØĩØŠ Ų„Ų„ØŖØˇŲØ§Ų„ ØšŲ†Ø¯ ØĒØŗØŦŲŠŲ„ Ø§Ų„ØŽØąŲˆØŦ ØŖŲˆ ØšŲ†Ø¯ Ø§ØŗØĒØŽØ¯Ø§Ų… ؈ØļØš Ø§Ų„ØĒØĩŲØ­ Ø§Ų„Ų…ØĒØŽŲŲŠ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">ØšØąØļ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">؊ØĒŲ… ØšØąØļ Ų†ŲˆØš Ø§Ų„ØšŲ…ŲŠŲ„ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">ØĒŲ… ØĨØŽŲØ§ØĄ Ų†ŲˆØš Ø§Ų„ØšŲ…ŲŠŲ„ ؁؊ ØĨØ­ØĩØ§ØĄØ§ØĒ ØĒŲ‚Ų†ŲŠØŠ</string>
<string name="revanced_spoof_video_streams_language_title">Ų„ØēØŠ Ø§Ų„Ø¨ØĢ Ø§Ų„Øĩ؈ØĒ؊ Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ Ų„Ų„ŲˆØ§Ų‚Øš Ø§Ų„Ø§ŲØĒØąØ§Øļ؊ 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>
</app>
<app id="twitch">

View File

@@ -30,6 +30,10 @@ Second \"item\" text"</string>
<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. -->
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
</patch>
<patch id="misc.debugging.enableDebuggingPatch">
</patch>
</app>
<app id="youtube">
<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.
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. -->
<!-- 'Shop' 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 id="layout.buttons.navigation.navigationButtonsPatch">
@@ -209,8 +214,6 @@ Second \"item\" text"</string>
</patch>
<patch id="misc.dimensions.spoof.spoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.gmsCoreSupportResourcePatch">
</patch>
<patch id="misc.hapticfeedback.disableHapticFeedbackPatch">
</patch>
<patch id="misc.gms.accountCredentialsInvalidTextPatch">
@@ -242,6 +245,21 @@ Second \"item\" text"</string>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch>
<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>
</app>
<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. -->
</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>
<!-- 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_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>
<string name="gms_core_dialog_continue_text">Davam et</string>
</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 id="youtube">
<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>
</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_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_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.
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 id="layout.hide.general.hideLayoutComponentsPatch">
<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_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>
<!-- '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. -->
<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>
@@ -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_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'. -->
<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. -->
<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>
@@ -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>
<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 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">
<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>
@@ -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_off">İlkin səs istifadəsi</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">Bu 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 id="video.quality.rememberVideoQualityPatch">
<!-- 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>
</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_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_title">Saxtakarlıq 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
â€ĸ Sabit səs səviyyəsi yoxdur
â€ĸ İlkin səsi məcbur etmə mÃŧmkÃŧn deyil"</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ Səs treki menyusu əlçatmazdÄąr
â€ĸ Sabit səs səviyyəsi yoxdur"</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_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_summary_on">Qəbuledici nÃļvÃŧ İstək ÃŧçÃŧn statistikada gÃļstərilir</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Qəbuledici nerd ÃŧçÃŧn Statistikada gizlidir</string>
<string name="revanced_spoof_video_streams_language_title">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>
</app>
<app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. -->
</patch>
<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. -->
<string name="gms_core_toast_not_installed_message">MicroG GmsCore ĐŊĐĩ ŅžŅŅ‚Đ°ĐģŅĐ˛Đ°ĐŊŅ‹. ĐŖŅŅ‚Đ°ĐģŅŽĐšŅ†Đĩ ŅĐŗĐž.</string>
<string name="gms_core_dialog_title">ĐŸĐ°Ņ‚Ņ€Đ°ĐąŅƒĐĩŅ†Ņ†Đ° дСĐĩŅĐŊĐŊĐĩ</string>
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
ĐĐ°Ņ†Ņ–ŅĐŊҖ҆Đĩ ĐēĐŊĐžĐŋĐē҃ \"ĐŸŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ\" Ņ– даСвОĐģŅŒŅ†Đĩ СĐŧŅĐŊŅ–Ņ†ŅŒ аĐŋ҂ҋĐŧŅ–ĐˇĐ°Ņ†Ņ‹ŅŽ."</string>
<string name="gms_core_dialog_continue_text">ĐŸŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ</string>
</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 id="youtube">
<patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊĐžĐ˛Ņ‹Đš ĐŋĐģĐĩĐšĐģĐ¸ŅŅ‚ Shorts вĐēĐģŅŽŅ‡ĐĩĐŊ</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_protobuffer_title">Đ‘ŅƒŅ„ĐĩŅ€ ĐŋŅ€Đ°Ņ‚Đ°ĐēĐžĐģ҃ Ņ‡Đ°ŅĐžĐŋŅ–ŅĐ°</string>
<string name="revanced_debug_protobuffer_summary_on">Đ–ŅƒŅ€ĐŊаĐģŅ‹ адĐģадĐēŅ– ŅžĐēĐģŅŽŅ‡Đ°ŅŽŅ†ŅŒ ĐŋŅ€Đ°Ņ‚Đ°ĐąŅƒŅ„ĐĩŅ€</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>
<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 id="layout.hide.general.hideLayoutComponentsPatch">
<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_summary_on">КĐŊĐžĐŋĐēа ĐēĐģŅ–Đŋа ŅŅ…Đ°Đ˛Đ°ĐŊа</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. -->
<string name="revanced_hide_save_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ \"Đ—Đ°Ņ…Đ°Đ˛Đ°Ņ†ŅŒ\"</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'. -->
<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. -->
<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>
@@ -1416,10 +1439,6 @@ Second \"item\" text"</string>
ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа Ņ€Đ°ĐˇĐąĐģаĐēĐ°Đ˛Đ°Ņ†ŅŒ йОĐģҌ҈ Đ˛Ņ‹ŅĐžĐēŅ–Ņ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">ĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°ĐŗĐ° ĐŧĐžĐļа ĐŋŅ€Ņ‹Đ˛Đĩҁ҆Җ да ĐŋҀҋĐŋŅ‹ĐŊĐēĐ°Ņž ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊŅ Đ˛Ņ–Đ´ŅĐ°, ĐŋĐ°ĐŗĐ°Ņ€ŅˆŅĐŊĐŊŅ Ņ‚ŅŅ€ĐŧŅ–ĐŊ҃ ҁĐģ҃ĐļĐąŅ‹ ĐąĐ°Ņ‚Đ°Ņ€ŅŅ– Ņ– ĐŊĐĩĐ˛ŅĐ´ĐžĐŧҋ҅ ĐŋĐ°ĐąĐžŅ‡ĐŊҋ҅ ŅŅ„ĐĩĐēŅ‚Đ°Ņž.</string>
</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">
<string name="revanced_disable_haptic_feedback_title">ĐĸаĐē҂ҋĐģҌĐŊĐ°Ņ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊĐ°Ņ ŅŅƒĐ˛ŅĐˇŅŒ</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_off">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐŊĐŊĐĩ Đ°ŅžĐ´Ņ‹Ņ‘ Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ–</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">Каб Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Ņ†ŅŒ ĐŗŅŅ‚Ņƒ Ņ„ŅƒĐŊĐēŅ†Ņ‹ŅŽ, СĐŧŅĐŊҖ҆Đĩ ĐŋĐ°Ņ€Đ°ĐŧĐĩ҂Ҁ \"ĐŸĐ°Đ´Ņ€Đ°ĐąĐģŅŅ†ŅŒ Đ˛Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅ–\" ĐŊа iOS TV</string>
<string name="revanced_force_original_audio_not_available">Каб Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°Ņ†ŅŒ ĐŗŅŅ‚ŅƒŅŽ Ņ„ŅƒĐŊĐēŅ†Ņ‹ŅŽ, СĐŧŅĐŊҖ҆Đĩ \'ПадĐŧĐĩĐŊа Đ˛Ņ–Đ´ŅĐ°ŅŅ‚Ņ€ŅƒĐŧĐĩĐŊŅŅž\' ĐŊа ĐģŅŽĐąĐžĐŗĐ° ĐēĐģŅ–ĐĩĐŊŅ‚Đ°, аĐēŅ€Đ°ĐŧŅ Android Studio</string>
</patch>
<patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1533,35 +1552,54 @@ Second \"item\" text"</string>
<string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃ ĐŊĐĩ ŅžĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_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">ĐŸĐžŅ‚ĐžĐēи видĐĩĐž ĐŋОддĐĩĐģаĐŊŅ‹</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_title">ĐŸĐ°ĐąĐžŅ‡ĐŊŅ‹Ņ ŅŅ„ĐĩĐē҂ҋ ĐŋĐ°Đ´Ņ€ĐžĐąĐēŅ–</string>
<string name="revanced_spoof_video_streams_about_android_title">ĐŸĐžĐąŅ–Ņ‡ĐŊŅ‹Ņ ŅŅ„ĐĩĐē҂ҋ ĐŋĐ°Đ´Ņ€ĐžĐąĐēŅ– Android</string>
<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_kids_videos">â€ĸ Đ”ĐˇŅ–Ņ†ŅŅ‡Ņ‹Ņ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐŗŅƒŅ†ŅŒ ĐŊĐĩ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°Ņ†Ņ†Đ° Ņž ŅŅ‚Đ°ĐŊĐĩ Đ˛Ņ‹Ņ…Đ°Đ´Ņƒ С аĐēĐ°ŅžĐŊŅ‚Đ° айО Ņž Ņ€ŅĐļŅ‹ĐŧĐĩ Ņ–ĐŊĐēĐžĐŗĐŊŅ–Ņ‚Đ°</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">ПаĐēĐ°ĐˇĐ°Ņ†ŅŒ ҃ ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">ĐĸŅ‹Đŋ ĐēĐģŅ–ĐĩĐŊŅ‚Đ° адĐģŅŽŅŅ‚Ņ€ĐžŅžĐ˛Đ°ĐĩŅ†Ņ†Đ° Ņž ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">КĐģŅ–ĐĩĐŊŅ‚ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹ Ņž ŅŅ‚Đ°Ņ‚Ņ‹ŅŅ‚Ņ‹Ņ†Ņ‹ Đ´ĐģŅ ҁĐŋĐĩŅ†Ņ‹ŅĐģŅ–ŅŅ‚Đ°Ņž</string>
<string name="revanced_spoof_video_streams_language_title">Мова ĐŗŅƒĐēавОК Đ´Đ°Ņ€ĐžĐļĐēŅ– Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ– Đ´ĐģŅ 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>
</app>
<app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. -->
</patch>
<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. -->
<string name="gms_core_toast_not_installed_message">GmsCore ĐŊĐĩ Đĩ иĐŊŅŅ‚Đ°ĐģĐ¸Ņ€Đ°ĐŊ. ИĐŊŅŅ‚Đ°ĐģĐ¸Ņ€Đ°ĐšŅ‚Đĩ ĐŗĐž.</string>
<string name="gms_core_dialog_title">ĐŅƒĐļĐŊĐž Đĩ Đ´ĐĩĐšŅŅ‚Đ˛Đ¸Đĩ</string>
@@ -84,6 +86,37 @@ Second \"item\" text"</string>
ДоĐēĐžŅĐŊĐĩŅ‚Đĩ ĐąŅƒŅ‚ĐžĐŊа Са ĐŋŅ€ĐžĐ´ŅŠĐģĐļаваĐŊĐĩ и Ņ€Đ°ĐˇŅ€Đĩ҈ĐĩŅ‚Đĩ ĐŋŅ€ĐžĐŧĐĩĐŊи в ĐžĐŋŅ‚Đ¸ĐŧĐ¸ĐˇĐ°Ņ†Đ¸ŅŅ‚Đ°."</string>
<string name="gms_core_dialog_continue_text">ĐŸŅ€ĐžĐ´ŅŠĐģĐļи</string>
</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 id="youtube">
<patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ Second \"item\" text"</string>
<string name="revanced_shorts_disable_background_playback_summary_off">ФОĐŊĐžĐ˛ĐžŅ‚Đž Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩ ĐŊа Shorts Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</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_protobuffer_title">Đ‘ŅƒŅ„ĐĩŅ€ ĐŊа ĐŋŅ€ĐžŅ‚ĐžĐēĐžĐģа Са Đ´ĐŊĐĩвĐŊиĐēа</string>
<string name="revanced_debug_protobuffer_summary_on">ФаКĐģОвĐĩ ҁ Đ´ĐŊĐĩвĐŊĐ¸Ņ†Đ¸ Са ĐŗŅ€Đĩ҈Đēи вĐēĐģŅŽŅ‡Đ˛Đ°Ņ‚ ĐąŅƒŅ„ĐĩŅ€Đ°</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>
<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 id="layout.hide.general.hideLayoutComponentsPatch">
<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_summary_on">Đ‘ŅƒŅ‚ĐžĐŊа Са ĐēĐģиĐŋ Đĩ ҁĐēŅ€Đ¸Ņ‚</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. -->
<string name="revanced_hide_save_button_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ЗаĐŋаСваĐŊĐĩ</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_off">МĐĩĐŊŅŽŅ‚Đž Са Đ¸ĐˇĐąĐžŅ€ ĐŊа ĐŅƒĐ´Đ¸Đž ҁĐĩ ĐŋĐžĐēаСва</string>
<!-- '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. -->
<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>
@@ -1415,10 +1438,6 @@ Second \"item\" text"</string>
АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐžŅ‚ĐēĐģŅŽŅ‡Đ¸ ĐŋĐž-Đ˛Đ¸ŅĐžĐēи видĐĩĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đ°"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">Đ Đ°ĐˇŅ€ĐĩŅˆĐ°Đ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа Ņ‚ĐžĐ˛Đ° ĐŧĐžĐļĐĩ да ĐŋŅ€Đ¸Ņ‡Đ¸ĐŊи ĐŋŅ€ĐĩĐēŅŠŅĐ˛Đ°ĐŊĐĩ ĐŊа Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩŅ‚Đž ĐŊа видĐĩĐž, вĐģĐžŅˆĐĩĐŊ ĐļĐ¸Đ˛ĐžŅ‚ ĐŊа ĐąĐ°Ņ‚ĐĩŅ€Đ¸ŅŅ‚Đ° и ĐŊĐĩиСвĐĩҁ҂ĐŊи ŅŅ‚Ņ€Đ°ĐŊĐ¸Ņ‡ĐŊи ĐĩŅ„ĐĩĐēŅ‚Đ¸.</string>
</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">
<string name="revanced_disable_haptic_feedback_title">Đ’Đ¸ĐąŅ€Đ°Ņ†Đ¸ĐžĐŊĐŊа ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа</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_off">ИСĐŋĐžĐģСваĐŊĐĩ ĐŊа Đ°ŅƒĐ´Đ¸Đž ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">За да иСĐŋĐžĐģĐˇĐ˛Đ°Ņ‚Đĩ Ņ‚Đ°ĐˇĐ¸ Ņ„ŅƒĐŊĐēŅ†Đ¸Ņ, ҁĐŧĐĩĐŊĐĩŅ‚Đĩ „ФаĐģŅˆĐ¸Ņ„Đ¸Ņ†Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸â€œ ĐŊа iOS TV</string>
<string name="revanced_force_original_audio_not_available">За да иСĐŋĐžĐģĐˇĐ˛Đ°Ņ‚Đĩ Ņ‚Đ°ĐˇĐ¸ Ņ„ŅƒĐŊĐēŅ†Đ¸Ņ, ĐŋŅ€ĐžĐŧĐĩĐŊĐĩŅ‚Đĩ \'ФаĐģŅˆĐ¸Ņ„Đ¸Ņ†Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа видĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸\' ĐŊа Đ˛ŅĐĩĐēи ĐēĐģиĐĩĐŊŅ‚, ĐžŅĐ˛ĐĩĐŊ Android Studio</string>
</patch>
<patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1532,35 +1551,54 @@ Second \"item\" text"</string>
<string name="revanced_slide_to_seek_summary_off">ĐĄĐģаКд Са ĐŋŅ€ĐĩĐ˛ŅŠŅ€Ņ‚Đ°ĐŊĐĩ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊ</string>
</patch>
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
<string name="revanced_spoof_video_streams_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">ВидĐĩĐž ĐŋĐžŅ‚ĐžŅ†Đ¸Ņ‚Đĩ ŅĐ° ĐŋОдĐŋŅ€Đ°Đ˛ĐĩĐŊи</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_title">ĐĄŅ‚Ņ€Đ°ĐŊĐ¸Ņ‡ĐŊи ĐĩŅ„ĐĩĐēŅ‚Đ¸ ĐžŅ‚ ĐŋОдĐŧĐĩĐŊŅĐŊĐĩŅ‚Đž</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
â€ĸ Ne e nali4na stabilna glasnost
â€ĸ Ne e nali4na forsirana originalna audio pista"</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ ЛиĐŋŅĐ˛Đ° ĐŧĐĩĐŊŅŽŅ‚Đž Са Đ°ŅƒĐ´Đ¸ĐžĐˇĐ°ĐŋĐ¸ŅĐ¸
â€ĸ ĐĄŅ‚Đ°ĐąĐ¸ĐģĐĩĐŊ ĐˇĐ˛ŅƒĐē ĐŊĐĩ Đĩ ĐŊаĐģĐ¸Ņ‡ĐĩĐŊ"</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_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_summary_on">TipŅŠŅ‚ na klienta se poka6va v Statistiki za nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">KlientŅŠŅ‚ e skriŅ‚ v Statistiki za nerds</string>
<string name="revanced_spoof_video_streams_language_title">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>
</app>
<app id="twitch">

View File

@@ -68,6 +68,8 @@ Second \"item\" text"</string>
and changes made here must also be made there. -->
</patch>
<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. -->
<string name="gms_core_toast_not_installed_message">MicroG GmsCore āχāύāĻ¸ā§āϟāϞ āĻ•āϰāĻž āĻšā§ŸāύāĻŋāĨ¤ āχāύāĻ¸ā§āϟāϞ āĻ•āϰ⧁āύāĨ¤</string>
<string name="gms_core_dialog_title">āĻĒāĻĻāĻ•ā§āώ⧇āĻĒ āĻĒā§āĻ°ā§Ÿā§‹āϜāύ</string>
@@ -84,6 +86,37 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
āϚāĻžāϞāĻŋāϝāĻŧ⧇ āϝāĻžāύ āĻŦā§‹āϤāĻžāĻŽāϟāĻŋ āĻŸā§āϝāĻžāĻĒ āĻ•āϰ⧁āύ āĻāĻŦāĻ‚ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāĻœā§‡āĻļāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞāĻŋ āĻ…āύ⧁āĻŽā§‹āĻĻāύ āĻ•āϰ⧁āύāĨ¤"</string>
<string name="gms_core_dialog_continue_text">āĻāĻ—āĻŋā§Ÿā§‡ āϝāĻžāύ</string>
</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 id="youtube">
<patch id="misc.settings.settingsPatch">
@@ -110,11 +143,6 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_shorts_disable_background_playback_summary_off">Shorts āĻŦā§āϝāĻžāĻ•āĻ—ā§āϰāĻžāωāĻ¨ā§āĻĄ āĻĒā§āϞ⧇ āϏāĻ•ā§āώāĻŽ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</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_protobuffer_title">āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϞāĻ—</string>
<string name="revanced_debug_protobuffer_summary_on">āĻĄāĻŋāĻŦāĻžāĻ— āϞāĻ— āĻĒā§āϰāĻŸā§‹āĻ•āϞ āĻŦāĻžāĻĢāĻžāϰ āϏāĻ‚āϝ⧁āĻ•ā§āϤ āĻ•āϰāĻŦ⧇</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>
<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 id="layout.hide.general.hideLayoutComponentsPatch">
<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_summary_on">āĻ•ā§āϞāĻŋāĻĒ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</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. -->
<string name="revanced_hide_save_button_title">āϏāĻ‚āϰāĻ•ā§āώāĻŖ āϞ⧁āĻ•āĻžāύ</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'. -->
<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. -->
<string name="revanced_hide_player_flyout_watch_in_vr_title">āĻ­āĻŋāφāϰ-āĻ āϘāĻĄāĻŧāĻŋ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">āĻ­āĻŋāφāϰ āĻŽā§‡āύ⧁āϤ⧇ āĻĻ⧇āϖ⧁āύ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
@@ -1411,10 +1434,6 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
āĻāϟāĻŋ āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āωāĻšā§āϚ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύāϗ⧁āϞāĻŋ āφāύāϞāĻ• āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇"</string>
<string name="revanced_spoof_device_dimensions_user_dialog_message">āĻāϟāĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻžāϰ āĻĢāϞ⧇ āφāĻĒāύāĻŋ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāϞāĻžāϰ āĻ•ā§āώ⧇āĻ¤ā§āϰ⧇ āφāϟāϕ⧇ āϚāϞāĻž, āĻ–āĻžāϰāĻžāĻĒ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āϞāĻžāχāĻĢ āĻāĻŦāĻ‚ āĻ…āϜāĻžāύāĻž āĻĒāĻžāĻ°ā§āĻļā§āĻŦ-āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻžāϰ āϏāĻŽā§āĻŽā§āĻ–āĻŋāύ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āύāĨ¤</string>
</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">
<string name="revanced_disable_haptic_feedback_title">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋ⧟āĻž</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_off">āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ…āĻĄāĻŋāĻ“ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϛ⧇</string>
<!-- 'Spoof video streams' should be the same translation used for 'revanced_spoof_video_streams_screen_title'. -->
<string name="revanced_force_original_audio_not_available">āĻāχ āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇, \'āĻ¸ā§āĻĒ⧁āĻĢ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰ⧀āĻŽ\' āϕ⧇ iOS TV-āϤ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
<string name="revanced_force_original_audio_not_available">āĻāχ āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāϟāĻŋ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϤ⧇, \'āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻŸā§āϰāĻŋāĻŽ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ\' āĻ…ā§āϝāĻžāĻ¨ā§āĻĄā§āϰāϝāĻŧ⧇āĻĄ āĻ¸ā§āϟ⧁āĻĄāĻŋāĻ“ āĻ›āĻžāĻĄāĻŧāĻž āĻ…āĻ¨ā§āϝ āϕ⧋āύ⧋ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āĻŸā§‡ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
</patch>
<patch id="video.quality.rememberVideoQualityPatch">
<!-- Translations should use the same text as 'revanced_custom_playback_speeds_auto'. -->
@@ -1528,35 +1547,54 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
<string name="revanced_slide_to_seek_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ‚āĻļ⧇ āϝ⧇āϤ⧇ āϟāĻžāύ⧁āύ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§ŸāύāĻŋ</string>
</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_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_title">āĻ¸ā§āĻĒ⧁āĻĢāĻŋāĻ‚ā§Ÿā§‡āϰ āĻĒāĻžāĻ°ā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž</string>
<string name="revanced_spoof_video_streams_about_android_title">Android āĻ¸ā§āĻĒ⧁āĻĢāĻŋāĻ‚āϝāĻŧ⧇āϰ āĻĒāĻžāĻ°ā§āĻļā§āĻŦāĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āύ⧇āχ
â€ĸ āĻ¸ā§āĻĨāĻŋāϰ āĻ­āϞāĻŋāωāĻŽ āĻĒāĻžāĻ“āϝāĻŧāĻž āϝāĻžāϝāĻŧ āύāĻž
â€ĸ āĻŽā§‚āϞ āĻ…āĻĄāĻŋāĻ“ āĻœā§‹āϰ āĻ•āϰ⧇ āϚāĻžāϞ⧁ āĻ•āϰāĻž āϝāĻžāϝāĻŧ āύāĻž"</string>
<string name="revanced_spoof_video_streams_about_android_summary">"â€ĸ āĻ…āĻĄāĻŋāĻ“ āĻŸā§āĻ°ā§āϝāĻžāĻ• āĻŽā§‡āύ⧁ āĻ…āύ⧁āĻĒāĻ¸ā§āĻĨāĻŋāϤ
â€ĸ āĻ¸ā§āĻĨāĻŋāϤāĻŋāĻļā§€āϞ āĻ­āϞāĻŋāωāĻŽ āωāĻĒāϞāĻŦā§āϧ āύ⧇āχ"</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_kids_videos">â€ĸ āϞāĻ—āφāωāϟ āĻ•āϰāĻž āĻšāϞ⧇ āĻŦāĻž āĻ›āĻĻā§āĻŽāĻŦ⧇āĻļā§€ āĻŽā§‹āĻĄā§‡ āĻŦāĻžāĻšā§āϚāĻžāĻĻ⧇āϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āϚāϞāϤ⧇ āύāĻžāĻ“ āĻĒāĻžāϰ⧇</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻĻ⧇āĻ–āĻžāύ</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āĻĒā§āϰāĻ•āĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāĻŦ⧇</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">āĻ¸ā§āĻŸā§āϝāĻžāϟāϏ āĻĢāϰ āύāĻžāĻ°ā§āĻĄāϏ⧇ āĻ•ā§āϞāĻžāϝāĻŧ⧇āĻ¨ā§āϟ āϞ⧁āĻ•āĻžāύ⧋ āĻšāĻŦ⧇</string>
<string name="revanced_spoof_video_streams_language_title">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>
</app>
<app id="twitch">

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