Compare commits

...

67 Commits

Author SHA1 Message Date
semantic-release-bot
e67f390e2b chore: Release v5.16.2-dev.1 [skip ci]
## [5.16.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.1...v5.16.2-dev.1) (2025-03-26)

### Bug Fixes

* **Facebook - Hide 'Sponsored Stories':** Constrain patch to latest compatible version ([#4657](https://github.com/ReVanced/revanced-patches/issues/4657)) ([4d910fe](4d910fea93))
2025-03-26 18:34:18 +00:00
LisoUseInAIKyrios
4d910fea93 fix(Facebook - Hide 'Sponsored Stories'): Constrain patch to latest compatible version (#4657) 2025-03-26 19:30:48 +01:00
semantic-release-bot
72adbe5519 chore: Release v5.16.1 [skip ci]
## [5.16.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.0...v5.16.1) (2025-03-26)

### Bug Fixes

* **Spotify - Unlock Premium:** Override streaming attribute attempting to fix streaming issues ([06be36c](06be36cddf))
2025-03-26 14:10:25 +00:00
oSumAtrIX
54d49b774e chore: Merge branch dev to main (#4650) 2025-03-26 15:08:18 +01:00
semantic-release-bot
283bb31567 chore: Release v5.16.1-dev.1 [skip ci]
## [5.16.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.0...v5.16.1-dev.1) (2025-03-26)

### Bug Fixes

* **Spotify - Unlock Premium:** Override streaming attribute attempting to fix streaming issues ([06be36c](06be36cddf))
2025-03-26 13:54:23 +00:00
semantic-release-bot
2724fcbd27 chore: Release v5.16.0 [skip ci]
# [5.16.0](https://github.com/ReVanced/revanced-patches/compare/v5.15.0...v5.16.0) (2025-03-26)

### Bug Fixes

* **YouTube - Settings:** System navigation bar is located above the settings ui on Android 15+ ([54eef22](54eef22ce7))

### Features

* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([5c5a1e4](5c5a1e4b8b))
* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([d5845ab](d5845abd08))
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([d8c276c](d8c276cf96))
2025-03-26 03:42:23 +00:00
oSumAtrIX
7c28193579 chore: Merge branch dev to main (#4628)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: ILoveOpenSourceApplications <117499019+ILoveOpenSourceApplications@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: Brosssh <tiabroch@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-03-26 04:39:27 +01:00
github-actions[bot]
cd1ee814c4 chore: Sync translations (#4645) 2025-03-26 04:30:29 +01:00
semantic-release-bot
d9ccd73b5f chore: Release v5.16.0-dev.2 [skip ci]
# [5.16.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.16.0-dev.1...v5.16.0-dev.2) (2025-03-26)

### Features

* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([5c5a1e4](5c5a1e4b8b))
2025-03-26 03:27:26 +00:00
oSumAtrIX
5c5a1e4b8b feat(Spotify): Add Unlock premium patch (#4644)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: Brosssh <tiabroch@gmail.com>
2025-03-26 04:24:47 +01:00
semantic-release-bot
66a2ee2416 chore: Release v5.16.0-dev.1 [skip ci]
# [5.16.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.15.0...v5.16.0-dev.1) (2025-03-24)

### Bug Fixes

* **YouTube - Settings:** System navigation bar is located above the settings ui on Android 15+ ([54eef22](54eef22ce7))

### Features

* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([d5845ab](d5845abd08))
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([d8c276c](d8c276cf96))
2025-03-24 16:26:47 +00:00
ILoveOpenSourceApplications
d8c276cf96 feat(YouTube - Video description): Add Hide AI-generated video summary (#4636) 2025-03-24 17:23:57 +01:00
ILoveOpenSourceApplications
d5845abd08 feat(YouTube - Comments): Add Hide AI Comments summary (#4634) 2025-03-24 17:23:12 +01:00
LisoUseInAIKyrios
54eef22ce7 fix(YouTube - Settings): System navigation bar is located above the settings ui on Android 15+ 2025-03-24 17:21:36 +01:00
ILoveOpenSourceApplications
e287bdc59d chore(YouTube): Use consistent strings (#4637) 2025-03-24 17:12:11 +01:00
LisoUseInAIKyrios
20a82ef956 chore: Remove duplicate language entry 2025-03-22 11:01:19 +01:00
semantic-release-bot
1e29da9e06 chore: Release v5.15.0 [skip ci]
# [5.15.0](https://github.com/ReVanced/revanced-patches/compare/v5.14.0...v5.15.0) (2025-03-21)

### Bug Fixes

* **YouTube - Spoof app version:** Change oldest spoof target to 19.01.34 ([54a7afa](54a7afa540))
* **YouTube - Spoof app version:** Remove broken spoof targets that YouTube no longer supports ([#4610](https://github.com/ReVanced/revanced-patches/issues/4610)) ([04a1700](04a170054e))
* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([df838ed](df838ed91d))

### Features

* **YouTube - SponsorBlock:** Add opacity setting to category segment colors ([#4582](https://github.com/ReVanced/revanced-patches/issues/4582)) ([bbf3a34](bbf3a34a2f))
2025-03-21 10:54:27 +00:00
LisoUseInAIKyrios
56e6a90a90 chore: Merge branch dev to main (#4615) 2025-03-21 11:51:03 +01:00
semantic-release-bot
76d32e21c2 chore: Release v5.15.0-dev.4 [skip ci]
# [5.15.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.3...v5.15.0-dev.4) (2025-03-21)

### Bug Fixes

* **YouTube - Spoof app version:** Change oldest spoof target to 19.01.34 ([54a7afa](54a7afa540))
2025-03-21 09:26:53 +00:00
LisoUseInAIKyrios
54a7afa540 fix(YouTube - Spoof app version): Change oldest spoof target to 19.01.34 2025-03-21 10:23:26 +01:00
LisoUseInAIKyrios
ef86438bac ci: Pull Crowdin strings less often 2025-03-21 10:21:16 +01:00
github-actions[bot]
0683cedac0 chore: Sync translations (#4626) 2025-03-21 10:18:28 +01:00
semantic-release-bot
35753410aa chore: Release v5.15.0-dev.3 [skip ci]
# [5.15.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.2...v5.15.0-dev.3) (2025-03-20)

### Bug Fixes

* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([df838ed](df838ed91d))
2025-03-20 11:17:31 +00:00
LisoUseInAIKyrios
df838ed91d fix(YouTube): Do not show restart prompt more than once if setting change is canceled 2025-03-20 12:14:31 +01:00
github-actions[bot]
8e494d26d4 chore: Sync translations (#4623) 2025-03-20 12:08:20 +01:00
LisoUseInAIKyrios
7d834e5421 refactor(YouTube - Spoof app version): Allow manually spoofing to 19.01 - 19.25 2025-03-20 09:57:29 +01:00
semantic-release-bot
60a31cf4e1 chore: Release v5.15.0-dev.2 [skip ci]
# [5.15.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.1...v5.15.0-dev.2) (2025-03-19)

### Bug Fixes

* **YouTube - Spoof app version:** Remove broken spoof targets that YouTube no longer supports ([#4610](https://github.com/ReVanced/revanced-patches/issues/4610)) ([04a1700](04a170054e))
2025-03-19 17:19:19 +00:00
github-actions[bot]
edb8bd66bc chore: Sync translations (#4616) 2025-03-19 18:16:05 +01:00
LisoUseInAIKyrios
04a170054e fix(YouTube - Spoof app version): Remove broken spoof targets that YouTube no longer supports (#4610) 2025-03-19 18:08:51 +01:00
semantic-release-bot
79e6349a69 chore: Release v5.15.0-dev.1 [skip ci]
# [5.15.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.14.0...v5.15.0-dev.1) (2025-03-19)

### Features

* **YouTube - SponsorBlock:** Add opacity setting to category segment colors ([#4582](https://github.com/ReVanced/revanced-patches/issues/4582)) ([bbf3a34](bbf3a34a2f))
2025-03-19 17:06:12 +00:00
LisoUseInAIKyrios
bbf3a34a2f feat(YouTube - SponsorBlock): Add opacity setting to category segment colors (#4582) 2025-03-19 18:02:06 +01:00
github-actions[bot]
1db7c49514 chore: Sync translations (#4614) 2025-03-19 18:00:52 +01:00
semantic-release-bot
ef0506a4f8 chore: Release v5.14.0 [skip ci]
# [5.14.0](https://github.com/ReVanced/revanced-patches/compare/v5.13.0...v5.14.0) (2025-03-09)

### Bug Fixes

* **Boost for reddit - Client spoof:** Use a different user agent to combat Reddit's API issues ([8d0bca3](8d0bca3b03))
* **YouTube - Change form factor:** Restore Automotive form factor watch history menu, channel pages, and community posts ([#4541](https://github.com/ReVanced/revanced-patches/issues/4541)) ([e2de2d8](e2de2d8d44))
* **YouTube - Hide ads:** Hide new type of buttoned ad ([#4528](https://github.com/ReVanced/revanced-patches/issues/4528)) ([67dcd09](67dcd091c4))
* **YouTube - Hide layout components:** Do not hide Movie/Courses start page content if 'Hide horizontal shelves' is enabled ([99879f6](99879f6e0a))
* **YouTube - Theme:** Resolve dark mode startup crash with Android 9.0 ([7adfc63](7adfc637dc))
* **YouTube:** Change language settings menu to use native language names ([#4568](https://github.com/ReVanced/revanced-patches/issues/4568)) ([e9bc201](e9bc201641))
* **YouTube:** Combine `Restore old video quality menu` and `Remember video quality` into `Video quality` patch ([#4552](https://github.com/ReVanced/revanced-patches/issues/4552)) ([ee5c830](ee5c830df8))

### Features

* **Infinity for Reddit:** Add support for package name on IzzyOnDroid ([#4554](https://github.com/ReVanced/revanced-patches/issues/4554)) ([df3dc1c](df3dc1c0b2))
* **Spotify:** Add `Spoof signature` patch ([#4576](https://github.com/ReVanced/revanced-patches/issues/4576)) ([f39e70c](f39e70c648))
* **YouTube - Remember video quality:** Add separate Shorts default quality settings ([#4543](https://github.com/ReVanced/revanced-patches/issues/4543)) ([2a67c31](2a67c312e1))
2025-03-09 12:21:22 +00:00
oSumAtrIX
9b38da35ff chore: Merge branch dev to main (#4540)
Co-authored-by: ILoveOpenSourceApplications <117499019+ILoveOpenSourceApplications@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: alieRN <45766489+aliernfrog@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-03-09 13:17:57 +01:00
github-actions[bot]
afdb771066 chore: Sync translations (#4577) 2025-03-09 14:14:53 +02:00
semantic-release-bot
1b2b536d2e chore: Release v5.14.0-dev.9 [skip ci]
# [5.14.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.8...v5.14.0-dev.9) (2025-03-09)

### Features

* **Spotify:** Add `Spoof signature` patch ([#4576](https://github.com/ReVanced/revanced-patches/issues/4576)) ([f39e70c](f39e70c648))
2025-03-09 12:10:11 +00:00
oSumAtrIX
f39e70c648 feat(Spotify): Add Spoof signature patch (#4576) 2025-03-09 13:06:53 +01:00
semantic-release-bot
556acdd9c1 chore: Release v5.14.0-dev.8 [skip ci]
# [5.14.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.7...v5.14.0-dev.8) (2025-03-09)

### Bug Fixes

* **YouTube - Theme:** Resolve dark mode startup crash with Android 9.0 ([7adfc63](7adfc637dc))
2025-03-09 09:32:12 +00:00
LisoUseInAIKyrios
7adfc637dc fix(YouTube - Theme): Resolve dark mode startup crash with Android 9.0 2025-03-09 11:29:17 +02:00
github-actions[bot]
9cc0c075ad chore: Sync translations (#4575) 2025-03-09 11:28:52 +02:00
semantic-release-bot
ead11e7f46 chore: Release v5.14.0-dev.7 [skip ci]
# [5.14.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.6...v5.14.0-dev.7) (2025-03-08)

### Bug Fixes

* **YouTube:** Change language settings menu to use native language names ([#4568](https://github.com/ReVanced/revanced-patches/issues/4568)) ([e9bc201](e9bc201641))
2025-03-08 18:45:38 +00:00
LisoUseInAIKyrios
e9bc201641 fix(YouTube): Change language settings menu to use native language names (#4568) 2025-03-08 20:42:48 +02:00
github-actions[bot]
99baedf355 chore: Sync translations (#4573) 2025-03-08 20:42:13 +02:00
semantic-release-bot
0338d0acd3 chore: Release v5.14.0-dev.6 [skip ci]
# [5.14.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.5...v5.14.0-dev.6) (2025-03-07)

### Bug Fixes

* **YouTube - Hide layout components:** Do not hide Movie/Courses start page content if 'Hide horizontal shelves' is enabled ([99879f6](99879f6e0a))
2025-03-07 17:40:21 +00:00
LisoUseInAIKyrios
99879f6e0a fix(YouTube - Hide layout components): Do not hide Movie/Courses start page content if 'Hide horizontal shelves' is enabled 2025-03-07 19:37:23 +02:00
github-actions[bot]
f0c70de602 chore: Sync translations (#4562) 2025-03-07 19:35:55 +02:00
LisoUseInAIKyrios
737ae07a06 refactor(YouTube): Sort no title preference group by first sub preference title 2025-03-06 21:15:29 +02:00
semantic-release-bot
2c51de59de chore: Release v5.14.0-dev.5 [skip ci]
# [5.14.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.4...v5.14.0-dev.5) (2025-03-06)

### Features

* **Infinity for Reddit:** Add support for package name on IzzyOnDroid ([#4554](https://github.com/ReVanced/revanced-patches/issues/4554)) ([df3dc1c](df3dc1c0b2))
2025-03-06 18:27:44 +00:00
ILoveOpenSourceApplications
df3dc1c0b2 feat(Infinity for Reddit): Add support for package name on IzzyOnDroid (#4554) 2025-03-06 20:24:54 +02:00
github-actions[bot]
074c948581 chore: Sync translations (#4556) 2025-03-06 20:24:22 +02:00
semantic-release-bot
2a88b1f895 chore: Release v5.14.0-dev.4 [skip ci]
# [5.14.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.3...v5.14.0-dev.4) (2025-03-06)

### Bug Fixes

* **YouTube:** Combine `Restore old video quality menu` and `Remember video quality` into `Video quality` patch ([#4552](https://github.com/ReVanced/revanced-patches/issues/4552)) ([ee5c830](ee5c830df8))
2025-03-06 12:59:39 +00:00
LisoUseInAIKyrios
ee5c830df8 fix(YouTube): Combine Restore old video quality menu and Remember video quality into Video quality patch (#4552) 2025-03-06 14:56:32 +02:00
semantic-release-bot
e63a4b31f3 chore: Release v5.14.0-dev.3 [skip ci]
# [5.14.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.2...v5.14.0-dev.3) (2025-03-06)

### Bug Fixes

* **Boost for reddit - Client spoof:** Use a different user agent to combat Reddit's API issues ([8d0bca3](8d0bca3b03))
2025-03-06 10:36:52 +00:00
oSumAtrIX
8d0bca3b03 fix(Boost for reddit - Client spoof): Use a different user agent to combat Reddit's API issues 2025-03-06 11:33:06 +01:00
semantic-release-bot
c162d65d5b chore: Release v5.14.0-dev.2 [skip ci]
# [5.14.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.1...v5.14.0-dev.2) (2025-03-06)

### Bug Fixes

* **YouTube - Hide ads:** Hide new type of buttoned ad ([#4528](https://github.com/ReVanced/revanced-patches/issues/4528)) ([67dcd09](67dcd091c4))
2025-03-06 09:30:51 +00:00
ILoveOpenSourceApplications
67dcd091c4 fix(YouTube - Hide ads): Hide new type of buttoned ad (#4528) 2025-03-06 11:27:37 +02:00
github-actions[bot]
ac5ce2d67f chore: Sync translations (#4553) 2025-03-06 11:26:20 +02:00
LisoUseInAIKyrios
4b78d056fd ci: Pull Crowdin strings less often
Crowdin is starting to give errors and pulling less often may help.
2025-03-06 11:25:22 +02:00
semantic-release-bot
f8c901b2c1 chore: Release v5.14.0-dev.1 [skip ci]
# [5.14.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.13.1-dev.1...v5.14.0-dev.1) (2025-03-06)

### Features

* **YouTube - Remember video quality:** Add separate Shorts default quality settings ([#4543](https://github.com/ReVanced/revanced-patches/issues/4543)) ([2a67c31](2a67c312e1))
2025-03-06 06:49:39 +00:00
alieRN
2a67c312e1 feat(YouTube - Remember video quality): Add separate Shorts default quality settings (#4543) 2025-03-06 08:46:33 +02:00
semantic-release-bot
a7eed30f46 chore: Release v5.13.1-dev.1 [skip ci]
## [5.13.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.13.0...v5.13.1-dev.1) (2025-03-06)

### Bug Fixes

* **YouTube - Change form factor:** Restore Automotive form factor watch history menu, channel pages, and community posts ([#4541](https://github.com/ReVanced/revanced-patches/issues/4541)) ([e2de2d8](e2de2d8d44))
2025-03-06 06:28:57 +00:00
LisoUseInAIKyrios
e2de2d8d44 fix(YouTube - Change form factor): Restore Automotive form factor watch history menu, channel pages, and community posts (#4541) 2025-03-06 08:26:09 +02:00
github-actions[bot]
7ebbf356c0 chore: Sync translations (#4550) 2025-03-06 08:25:49 +02:00
ILoveOpenSourceApplications
2ced5c6e2a refactor(YouTube): Use more consistent strings (#4526) 2025-03-05 08:55:44 +02:00
semantic-release-bot
4a090ba659 chore: Release v5.13.0 [skip ci]
# [5.13.0](https://github.com/ReVanced/revanced-patches/compare/v5.12.0...v5.13.0) (2025-03-03)

### Bug Fixes

* **TikTok:** Resolve startup app crash ([3c52ab8](3c52ab8017))
* **TikTok:** Resolve startup app crash ([c817977](c8179776ed))
* **TikTok:** Resolve startup app crash ([d5aab3d](d5aab3d464))
* **TikTok:** Resolve startup app crash ([348f7e1](348f7e12cb))
* **YouTube - Copy video URL:** Use correct button ordering ([d77d5bf](d77d5bfbdd))
* **YouTube - Hide filter bar:** Fix `Hide in feed` not working in subscriptions feed ([#4512](https://github.com/ReVanced/revanced-patches/issues/4512)) ([1b60a72](1b60a72ede))
* **YouTube - Hide layout components:** Do not hide 'Show anyway' button in search results ([94fb367](94fb367618))
* **YouTube - Hide player components:** Show correct end video thumbnail if `Hide end screen suggested video` is enabled ([#4502](https://github.com/ReVanced/revanced-patches/issues/4502)) ([7cc939a](7cc939ab03))
* **YouTube - Hide video action buttons:** Move 'Disable Like and Subscribe glow' to action buttons settings menu ([7991c80](7991c80129))
* **YouTube - Return YouTube Dislike:** Use correct number formatting if using a different ReVanced language ([4ae1155](4ae1155e51))
* **YouTube - Spoof app version:** Force old settings menus if spoofing to older app targets ([#4490](https://github.com/ReVanced/revanced-patches/issues/4490)) ([0c0bbb8](0c0bbb8713))
* **YouTube - Spoof video streams:** Resolve playback issues with dynamic player config ([#4521](https://github.com/ReVanced/revanced-patches/issues/4521)) ([cbbf474](cbbf474c50))
* **YouTube - Swipe controls:** Adjust the overlay text size ([#4503](https://github.com/ReVanced/revanced-patches/issues/4503)) ([329f993](329f993024))
* **YouTube:** Do not hide player controls when using double tap to skip forward ([#4487](https://github.com/ReVanced/revanced-patches/issues/4487)) ([e664a24](e664a24f73))
* **YouTube:** Fix player button fade out animations ([#4469](https://github.com/ReVanced/revanced-patches/issues/4469)) ([a2c79f1](a2c79f1349))
* **YouTube:** Resolve button flickering when taping seekbar ([#4500](https://github.com/ReVanced/revanced-patches/issues/4500)) ([f5dd902](f5dd902915))

### Features

* **Infinity for Reddit:** Add support for Infinity for Reddit Plus ([#4511](https://github.com/ReVanced/revanced-patches/issues/4511)) ([fb8dbb4](fb8dbb4723))
* **NU.nl:** Add `Hide ads` and `Spoof Certificate` patch ([#4368](https://github.com/ReVanced/revanced-patches/issues/4368)) ([93ea250](93ea250bf3))
* **YouTube - Navigation buttons:** Add 'Hide notifications' setting ([#4485](https://github.com/ReVanced/revanced-patches/issues/4485)) ([d6eae01](d6eae01e12))
* **YouTube - Swipe controls:** Swipe controls UI improvements ([#4422](https://github.com/ReVanced/revanced-patches/issues/4422)) ([3548359](354835966d))
2025-03-03 07:01:16 +00:00
LisoUseInAIKyrios
cb609a6d9d chore: Merge branch dev to main (#4470) 2025-03-03 08:57:51 +02:00
github-actions[bot]
42e6de9e8f chore: Sync translations (#4525) 2025-03-03 08:55:55 +02:00
171 changed files with 4029 additions and 5329 deletions

View File

@@ -2,7 +2,7 @@ name: Pull strings
on:
schedule:
- cron: "0 */6 * * *"
- cron: "0 */12 * * *"
workflow_dispatch:
jobs:

View File

@@ -1,3 +1,220 @@
## [5.16.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.1...v5.16.2-dev.1) (2025-03-26)
### Bug Fixes
* **Facebook - Hide 'Sponsored Stories':** Constrain patch to latest compatible version ([#4657](https://github.com/ReVanced/revanced-patches/issues/4657)) ([46bd1c8](https://github.com/ReVanced/revanced-patches/commit/46bd1c829acd5f83600025e0ceb7d482ae80be69))
## [5.16.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.0...v5.16.1) (2025-03-26)
### Bug Fixes
* **Spotify - Unlock Premium:** Override streaming attribute attempting to fix streaming issues ([06be36c](https://github.com/ReVanced/revanced-patches/commit/06be36cddf3430b4179dff696b3d15718cd6963b))
## [5.16.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.16.0...v5.16.1-dev.1) (2025-03-26)
### Bug Fixes
* **Spotify - Unlock Premium:** Override streaming attribute attempting to fix streaming issues ([06be36c](https://github.com/ReVanced/revanced-patches/commit/06be36cddf3430b4179dff696b3d15718cd6963b))
# [5.16.0](https://github.com/ReVanced/revanced-patches/compare/v5.15.0...v5.16.0) (2025-03-26)
### Bug Fixes
* **YouTube - Settings:** System navigation bar is located above the settings ui on Android 15+ ([f7497be](https://github.com/ReVanced/revanced-patches/commit/f7497be2c5e4abcde6eb55b84955124a28f55cae))
### Features
* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([f048c50](https://github.com/ReVanced/revanced-patches/commit/f048c50e56fc1f5a5c607860be4206ef83b528fe))
* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([e9b7f26](https://github.com/ReVanced/revanced-patches/commit/e9b7f263f739bd130f6ea79913851a52355977c5))
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([521fd48](https://github.com/ReVanced/revanced-patches/commit/521fd48602432ab436d8711c19d7130b2b05af12))
# [5.16.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.16.0-dev.1...v5.16.0-dev.2) (2025-03-26)
### Features
* **Spotify:** Add `Unlock premium` patch ([#4644](https://github.com/ReVanced/revanced-patches/issues/4644)) ([f048c50](https://github.com/ReVanced/revanced-patches/commit/f048c50e56fc1f5a5c607860be4206ef83b528fe))
# [5.16.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.15.0...v5.16.0-dev.1) (2025-03-24)
### Bug Fixes
* **YouTube - Settings:** System navigation bar is located above the settings ui on Android 15+ ([f7497be](https://github.com/ReVanced/revanced-patches/commit/f7497be2c5e4abcde6eb55b84955124a28f55cae))
### Features
* **YouTube - Comments:** Add `Hide AI Comments summary` ([#4634](https://github.com/ReVanced/revanced-patches/issues/4634)) ([e9b7f26](https://github.com/ReVanced/revanced-patches/commit/e9b7f263f739bd130f6ea79913851a52355977c5))
* **YouTube - Video description:** Add `Hide AI-generated video summary` ([#4636](https://github.com/ReVanced/revanced-patches/issues/4636)) ([521fd48](https://github.com/ReVanced/revanced-patches/commit/521fd48602432ab436d8711c19d7130b2b05af12))
# [5.15.0](https://github.com/ReVanced/revanced-patches/compare/v5.14.0...v5.15.0) (2025-03-21)
### Bug Fixes
* **YouTube - Spoof app version:** Change oldest spoof target to 19.01.34 ([5012439](https://github.com/ReVanced/revanced-patches/commit/5012439a8e53b2a4ab5e85c47976e1ab28a51208))
* **YouTube - Spoof app version:** Remove broken spoof targets that YouTube no longer supports ([#4610](https://github.com/ReVanced/revanced-patches/issues/4610)) ([883fbe7](https://github.com/ReVanced/revanced-patches/commit/883fbe71233c57cb1241e57c122b43f40722acc7))
* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([49797fe](https://github.com/ReVanced/revanced-patches/commit/49797fe8d0c4a0981ef621a31356c4315ae3777b))
### Features
* **YouTube - SponsorBlock:** Add opacity setting to category segment colors ([#4582](https://github.com/ReVanced/revanced-patches/issues/4582)) ([6e8ffba](https://github.com/ReVanced/revanced-patches/commit/6e8ffbade9e03658f725622631e44dabf2995861))
# [5.15.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.3...v5.15.0-dev.4) (2025-03-21)
### Bug Fixes
* **YouTube - Spoof app version:** Change oldest spoof target to 19.01.34 ([5012439](https://github.com/ReVanced/revanced-patches/commit/5012439a8e53b2a4ab5e85c47976e1ab28a51208))
# [5.15.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.2...v5.15.0-dev.3) (2025-03-20)
### Bug Fixes
* **YouTube:** Do not show restart prompt more than once if setting change is canceled ([49797fe](https://github.com/ReVanced/revanced-patches/commit/49797fe8d0c4a0981ef621a31356c4315ae3777b))
# [5.15.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.15.0-dev.1...v5.15.0-dev.2) (2025-03-19)
### Bug Fixes
* **YouTube - Spoof app version:** Remove broken spoof targets that YouTube no longer supports ([#4610](https://github.com/ReVanced/revanced-patches/issues/4610)) ([883fbe7](https://github.com/ReVanced/revanced-patches/commit/883fbe71233c57cb1241e57c122b43f40722acc7))
# [5.15.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.14.0...v5.15.0-dev.1) (2025-03-19)
### Features
* **YouTube - SponsorBlock:** Add opacity setting to category segment colors ([#4582](https://github.com/ReVanced/revanced-patches/issues/4582)) ([6e8ffba](https://github.com/ReVanced/revanced-patches/commit/6e8ffbade9e03658f725622631e44dabf2995861))
# [5.14.0](https://github.com/ReVanced/revanced-patches/compare/v5.13.0...v5.14.0) (2025-03-09)
### Bug Fixes
* **Boost for reddit - Client spoof:** Use a different user agent to combat Reddit's API issues ([5d3c817](https://github.com/ReVanced/revanced-patches/commit/5d3c8175b34a3f6ae2732b25db0851773a8c000d))
* **YouTube - Change form factor:** Restore Automotive form factor watch history menu, channel pages, and community posts ([#4541](https://github.com/ReVanced/revanced-patches/issues/4541)) ([aa5c001](https://github.com/ReVanced/revanced-patches/commit/aa5c001968446e5270c756256724e917009612cd))
* **YouTube - Hide ads:** Hide new type of buttoned ad ([#4528](https://github.com/ReVanced/revanced-patches/issues/4528)) ([4387a7b](https://github.com/ReVanced/revanced-patches/commit/4387a7b131f49729e902e008bb4cec073635c040))
* **YouTube - Hide layout components:** Do not hide Movie/Courses start page content if 'Hide horizontal shelves' is enabled ([62a6164](https://github.com/ReVanced/revanced-patches/commit/62a6164b88b64200b517a5ba6b800d8214dbbad8))
* **YouTube - Theme:** Resolve dark mode startup crash with Android 9.0 ([741c2d5](https://github.com/ReVanced/revanced-patches/commit/741c2d59406f5d602554bb3a3c0b8982f42848b4))
* **YouTube:** Change language settings menu to use native language names ([#4568](https://github.com/ReVanced/revanced-patches/issues/4568)) ([6f3f8fd](https://github.com/ReVanced/revanced-patches/commit/6f3f8fdce05501e4fa4423c2170a916fbea3b199))
* **YouTube:** Combine `Restore old video quality menu` and `Remember video quality` into `Video quality` patch ([#4552](https://github.com/ReVanced/revanced-patches/issues/4552)) ([ee67b76](https://github.com/ReVanced/revanced-patches/commit/ee67b763d5c5947a5b1ef4420b1efa820ed6af83))
### Features
* **Infinity for Reddit:** Add support for package name on IzzyOnDroid ([#4554](https://github.com/ReVanced/revanced-patches/issues/4554)) ([cf9f959](https://github.com/ReVanced/revanced-patches/commit/cf9f959923076c10a7f0a29f6ba277f5a055ec07))
* **Spotify:** Add `Spoof signature` patch ([#4576](https://github.com/ReVanced/revanced-patches/issues/4576)) ([3646c70](https://github.com/ReVanced/revanced-patches/commit/3646c70556b67a6b7ecf9b86869ebf03c3611333))
* **YouTube - Remember video quality:** Add separate Shorts default quality settings ([#4543](https://github.com/ReVanced/revanced-patches/issues/4543)) ([88142ab](https://github.com/ReVanced/revanced-patches/commit/88142ab464192b564b1b8d56a6b45663f77f5e00))
# [5.14.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.8...v5.14.0-dev.9) (2025-03-09)
### Features
* **Spotify:** Add `Spoof signature` patch ([#4576](https://github.com/ReVanced/revanced-patches/issues/4576)) ([3646c70](https://github.com/ReVanced/revanced-patches/commit/3646c70556b67a6b7ecf9b86869ebf03c3611333))
# [5.14.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.7...v5.14.0-dev.8) (2025-03-09)
### Bug Fixes
* **YouTube - Theme:** Resolve dark mode startup crash with Android 9.0 ([741c2d5](https://github.com/ReVanced/revanced-patches/commit/741c2d59406f5d602554bb3a3c0b8982f42848b4))
# [5.14.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.6...v5.14.0-dev.7) (2025-03-08)
### Bug Fixes
* **YouTube:** Change language settings menu to use native language names ([#4568](https://github.com/ReVanced/revanced-patches/issues/4568)) ([6f3f8fd](https://github.com/ReVanced/revanced-patches/commit/6f3f8fdce05501e4fa4423c2170a916fbea3b199))
# [5.14.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.5...v5.14.0-dev.6) (2025-03-07)
### Bug Fixes
* **YouTube - Hide layout components:** Do not hide Movie/Courses start page content if 'Hide horizontal shelves' is enabled ([62a6164](https://github.com/ReVanced/revanced-patches/commit/62a6164b88b64200b517a5ba6b800d8214dbbad8))
# [5.14.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.4...v5.14.0-dev.5) (2025-03-06)
### Features
* **Infinity for Reddit:** Add support for package name on IzzyOnDroid ([#4554](https://github.com/ReVanced/revanced-patches/issues/4554)) ([cf9f959](https://github.com/ReVanced/revanced-patches/commit/cf9f959923076c10a7f0a29f6ba277f5a055ec07))
# [5.14.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.3...v5.14.0-dev.4) (2025-03-06)
### Bug Fixes
* **YouTube:** Combine `Restore old video quality menu` and `Remember video quality` into `Video quality` patch ([#4552](https://github.com/ReVanced/revanced-patches/issues/4552)) ([ee67b76](https://github.com/ReVanced/revanced-patches/commit/ee67b763d5c5947a5b1ef4420b1efa820ed6af83))
# [5.14.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.2...v5.14.0-dev.3) (2025-03-06)
### Bug Fixes
* **Boost for reddit - Client spoof:** Use a different user agent to combat Reddit's API issues ([5d3c817](https://github.com/ReVanced/revanced-patches/commit/5d3c8175b34a3f6ae2732b25db0851773a8c000d))
# [5.14.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.14.0-dev.1...v5.14.0-dev.2) (2025-03-06)
### Bug Fixes
* **YouTube - Hide ads:** Hide new type of buttoned ad ([#4528](https://github.com/ReVanced/revanced-patches/issues/4528)) ([4387a7b](https://github.com/ReVanced/revanced-patches/commit/4387a7b131f49729e902e008bb4cec073635c040))
# [5.14.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.13.1-dev.1...v5.14.0-dev.1) (2025-03-06)
### Features
* **YouTube - Remember video quality:** Add separate Shorts default quality settings ([#4543](https://github.com/ReVanced/revanced-patches/issues/4543)) ([88142ab](https://github.com/ReVanced/revanced-patches/commit/88142ab464192b564b1b8d56a6b45663f77f5e00))
## [5.13.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.13.0...v5.13.1-dev.1) (2025-03-06)
### Bug Fixes
* **YouTube - Change form factor:** Restore Automotive form factor watch history menu, channel pages, and community posts ([#4541](https://github.com/ReVanced/revanced-patches/issues/4541)) ([aa5c001](https://github.com/ReVanced/revanced-patches/commit/aa5c001968446e5270c756256724e917009612cd))
# [5.13.0](https://github.com/ReVanced/revanced-patches/compare/v5.12.0...v5.13.0) (2025-03-03)
### Bug Fixes
* **TikTok:** Resolve startup app crash ([18c0fc2](https://github.com/ReVanced/revanced-patches/commit/18c0fc2a7f186f50a904fd25dbaa739abdd24993))
* **TikTok:** Resolve startup app crash ([6466398](https://github.com/ReVanced/revanced-patches/commit/64663983b84de1f28636205f61bf0a24c83968d1))
* **TikTok:** Resolve startup app crash ([c14bc24](https://github.com/ReVanced/revanced-patches/commit/c14bc244550de30eca975ca7c09e8eb0c47534b5))
* **TikTok:** Resolve startup app crash ([d700076](https://github.com/ReVanced/revanced-patches/commit/d7000768a5e5a688c9f4e48858ac34e352222c1e))
* **YouTube - Copy video URL:** Use correct button ordering ([5e622cc](https://github.com/ReVanced/revanced-patches/commit/5e622ccf66d34af31c6026fa7f4d332460c6ecb0))
* **YouTube - Hide filter bar:** Fix `Hide in feed` not working in subscriptions feed ([#4512](https://github.com/ReVanced/revanced-patches/issues/4512)) ([634d0ee](https://github.com/ReVanced/revanced-patches/commit/634d0ee12e31491c7ee1d4ceb002daf8366a3c15))
* **YouTube - Hide layout components:** Do not hide 'Show anyway' button in search results ([4ac8854](https://github.com/ReVanced/revanced-patches/commit/4ac8854b99808a8957f3b0b7438e1e0cdedffbaf))
* **YouTube - Hide player components:** Show correct end video thumbnail if `Hide end screen suggested video` is enabled ([#4502](https://github.com/ReVanced/revanced-patches/issues/4502)) ([6c4885a](https://github.com/ReVanced/revanced-patches/commit/6c4885a1d5dfff50100b01840b5552d92e83ee4a))
* **YouTube - Hide video action buttons:** Move 'Disable Like and Subscribe glow' to action buttons settings menu ([29b265d](https://github.com/ReVanced/revanced-patches/commit/29b265d8fdaa48502650be9623bfc518a57a0bb1))
* **YouTube - Return YouTube Dislike:** Use correct number formatting if using a different ReVanced language ([edf66f4](https://github.com/ReVanced/revanced-patches/commit/edf66f4e16d46156cb8b8e31d18cb8dbcb87737e))
* **YouTube - Spoof app version:** Force old settings menus if spoofing to older app targets ([#4490](https://github.com/ReVanced/revanced-patches/issues/4490)) ([45e7c46](https://github.com/ReVanced/revanced-patches/commit/45e7c46dd9c70c926b8b1a97ada668f90f5f6f8c))
* **YouTube - Spoof video streams:** Resolve playback issues with dynamic player config ([#4521](https://github.com/ReVanced/revanced-patches/issues/4521)) ([647e764](https://github.com/ReVanced/revanced-patches/commit/647e7642efc0c00db17ccb6a620d1c96ccf4afed))
* **YouTube - Swipe controls:** Adjust the overlay text size ([#4503](https://github.com/ReVanced/revanced-patches/issues/4503)) ([6dc4bf7](https://github.com/ReVanced/revanced-patches/commit/6dc4bf75e09ed6f05534919d7b769b720043abce))
* **YouTube:** Do not hide player controls when using double tap to skip forward ([#4487](https://github.com/ReVanced/revanced-patches/issues/4487)) ([63fe870](https://github.com/ReVanced/revanced-patches/commit/63fe870d48ca2217327b952bde241b7f16ced850))
* **YouTube:** Fix player button fade out animations ([#4469](https://github.com/ReVanced/revanced-patches/issues/4469)) ([bf8e775](https://github.com/ReVanced/revanced-patches/commit/bf8e7759f9bdbdfef419a879fb3dd7cf0dff0098))
* **YouTube:** Resolve button flickering when taping seekbar ([#4500](https://github.com/ReVanced/revanced-patches/issues/4500)) ([1f08047](https://github.com/ReVanced/revanced-patches/commit/1f08047b48cc9555a4887d16ec7219a55a77251f))
### Features
* **Infinity for Reddit:** Add support for Infinity for Reddit Plus ([#4511](https://github.com/ReVanced/revanced-patches/issues/4511)) ([d74732b](https://github.com/ReVanced/revanced-patches/commit/d74732b7596104321bde263201d95649e4bd0eee))
* **NU.nl:** Add `Hide ads` and `Spoof Certificate` patch ([#4368](https://github.com/ReVanced/revanced-patches/issues/4368)) ([f3268fb](https://github.com/ReVanced/revanced-patches/commit/f3268fb03ca25fb5465e36015b6c9dec2c84a655))
* **YouTube - Navigation buttons:** Add 'Hide notifications' setting ([#4485](https://github.com/ReVanced/revanced-patches/issues/4485)) ([506d241](https://github.com/ReVanced/revanced-patches/commit/506d2414bbc760e764e5a514b32926083d6ecb6b))
* **YouTube - Swipe controls:** Swipe controls UI improvements ([#4422](https://github.com/ReVanced/revanced-patches/issues/4422)) ([198e4d2](https://github.com/ReVanced/revanced-patches/commit/198e4d2a2315c24a09eb9ecfefbd131a75384d2c))
# [5.13.0-dev.19](https://github.com/ReVanced/revanced-patches/compare/v5.13.0-dev.18...v5.13.0-dev.19) (2025-03-02)

View File

@@ -8,6 +8,9 @@ public enum AppLanguage {
*/
DEFAULT,
// Languages codes not included with YouTube, but are translated on Crowdin
GA,
// Language codes found in locale_config.xml
// All region specific variants have been removed.
AF,

View File

@@ -22,12 +22,23 @@ import app.revanced.extension.shared.settings.Setting;
@SuppressWarnings("deprecation")
public abstract class AbstractPreferenceFragment extends PreferenceFragment {
/**
* Indicates that if a preference changes,
* to apply the change from the Setting to the UI component.
*/
public static boolean settingImportInProgress;
/**
* Prevents recursive calls during preference <-> UI syncing from showing extra dialogs.
*/
private static boolean updatingPreference;
/**
* Used to prevent showing reboot dialog, if user cancels a setting user dialog.
*/
private static boolean showingUserDialogMessage;
/**
* Confirm and restart dialog button text and title.
* Set by subclasses if Strings cannot be added as a resource.
@@ -35,13 +46,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
@Nullable
protected static String restartDialogButtonText, restartDialogTitle, confirmDialogTitle;
/**
* Used to prevent showing reboot dialog, if user cancels a setting user dialog.
*/
private boolean showingUserDialogMessage;
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
try {
if (updatingPreference) {
Logger.printDebug(() -> "Ignoring preference change as sync is in progress");
return;
}
Setting<?> setting = Setting.getSettingFromPath(Objects.requireNonNull(str));
if (setting == null) {
return;
@@ -63,10 +74,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
}
}
updatingPreference = true;
// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
// Updating here can can cause a recursive call back into this same method.
updatePreference(pref, setting, true, settingImportInProgress);
// Update any other preference availability that may now be different.
updateUIAvailability();
updatingPreference = false;
} catch (Exception ex) {
Logger.printException(() -> "OnSharedPreferenceChangeListener failure", ex);
}
@@ -97,7 +111,9 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
if (confirmDialogTitle == null) {
confirmDialogTitle = str("revanced_settings_confirm_user_dialog_title");
}
showingUserDialogMessage = true;
new AlertDialog.Builder(context)
.setTitle(confirmDialogTitle)
.setMessage(Objects.requireNonNull(setting.userDialogMessage).toString())
@@ -141,14 +157,16 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
* @return If the preference is currently set to the default value of the Setting.
*/
protected boolean prefIsSetToDefault(Preference pref, Setting<?> setting) {
Object defaultValue = setting.defaultValue;
if (pref instanceof SwitchPreference switchPref) {
return switchPref.isChecked() == (Boolean) setting.defaultValue;
return switchPref.isChecked() == (Boolean) defaultValue;
}
String defaultValueString = defaultValue.toString();
if (pref instanceof EditTextPreference editPreference) {
return editPreference.getText().equals(setting.defaultValue.toString());
return editPreference.getText().equals(defaultValueString);
}
if (pref instanceof ListPreference listPref) {
return listPref.getValue().equals(setting.defaultValue.toString());
return listPref.getValue().equals(defaultValueString);
}
throw new IllegalStateException("Must override method to handle "
@@ -158,16 +176,16 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
/**
* Syncs all UI Preferences to any {@link Setting} they represent.
*/
private void updatePreferenceScreen(@NonNull PreferenceScreen screen,
private void updatePreferenceScreen(@NonNull PreferenceGroup group,
boolean syncSettingValue,
boolean applySettingToPreference) {
// Alternatively this could iterate thru all Settings and check for any matching Preferences,
// but there are many more Settings than UI preferences so it's more efficient to only check
// the Preferences.
for (int i = 0, prefCount = screen.getPreferenceCount(); i < prefCount; i++) {
Preference pref = screen.getPreference(i);
if (pref instanceof PreferenceScreen) {
updatePreferenceScreen((PreferenceScreen) pref, syncSettingValue, applySettingToPreference);
for (int i = 0, prefCount = group.getPreferenceCount(); i < prefCount; i++) {
Preference pref = group.getPreference(i);
if (pref instanceof PreferenceGroup subGroup) {
updatePreferenceScreen(subGroup, syncSettingValue, applySettingToPreference);
} else if (pref.hasKey()) {
String key = pref.getKey();
Setting<?> setting = Setting.getSettingFromPath(key);
@@ -255,7 +273,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
}
}
public static void showRestartDialog(@NonNull final Context context) {
public static void showRestartDialog(Context context) {
Utils.verifyOnMainThread();
if (restartDialogTitle == null) {
restartDialogTitle = str("revanced_settings_restart_title");
@@ -263,6 +281,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
if (restartDialogButtonText == null) {
restartDialogButtonText = str("revanced_settings_restart");
}
new AlertDialog.Builder(context)
.setMessage(restartDialogTitle)
.setPositiveButton(restartDialogButtonText, (dialog, id)

View File

@@ -0,0 +1,54 @@
package app.revanced.extension.shared.settings.preference;
import android.annotation.SuppressLint;
import android.content.Context;
import android.preference.PreferenceCategory;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
* Empty preference category with no title, used to organize and group related preferences together.
*/
@SuppressWarnings({"unused", "deprecation"})
public class NoTitlePreferenceCategory extends PreferenceCategory {
public NoTitlePreferenceCategory(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoTitlePreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public NoTitlePreferenceCategory(Context context) {
super(context);
}
@Override
@SuppressLint("MissingSuperCall")
protected View onCreateView(ViewGroup parent) {
// Return an zero-height view to eliminate empty title space.
return new View(getContext());
}
@Override
public CharSequence getTitle() {
// Title can be used for sorting. Return the first sub preference title.
if (getPreferenceCount() > 0) {
return getPreference(0).getTitle();
}
return super.getTitle();
}
@Override
public int getTitleRes() {
if (getPreferenceCount() > 0) {
return getPreference(0).getTitleRes();
}
return super.getTitleRes();
}
}

View File

@@ -1,5 +1,7 @@
package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Bundle;
@@ -8,17 +10,23 @@ import android.util.AttributeSet;
import android.widget.Button;
import android.widget.EditText;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.Logger;
import androidx.annotation.Nullable;
import java.util.Objects;
import static app.revanced.extension.shared.StringRef.str;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.Setting;
@SuppressWarnings({"unused", "deprecation"})
public class ResettableEditTextPreference extends EditTextPreference {
/**
* Setting to reset.
*/
@Nullable
private Setting<?> setting;
public ResettableEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@@ -32,12 +40,22 @@ public class ResettableEditTextPreference extends EditTextPreference {
super(context);
}
public void setSetting(@Nullable Setting<?> setting) {
this.setting = setting;
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
Utils.setEditTextDialogTheme(builder);
Setting<?> setting = Setting.getSettingFromPath(getKey());
if (setting == null) {
String key = getKey();
if (key != null) {
setting = Setting.getSettingFromPath(key);
}
}
if (setting != null) {
builder.setNeutralButton(str("revanced_settings_reset"), null);
}
@@ -54,8 +72,7 @@ public class ResettableEditTextPreference extends EditTextPreference {
}
button.setOnClickListener(v -> {
try {
Setting<?> setting = Objects.requireNonNull(Setting.getSettingFromPath(getKey()));
String defaultStringValue = setting.defaultValue.toString();
String defaultStringValue = Objects.requireNonNull(setting).defaultValue.toString();
EditText editText = getEditText();
editText.setText(defaultStringValue);
editText.setSelection(defaultStringValue.length()); // move cursor to end of text

View File

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

View File

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

View File

@@ -0,0 +1,17 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
}
android {
namespace = "app.revanced.extension"
compileSdk = 34
defaultConfig {
minSdk = 26
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}

View File

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

View File

@@ -0,0 +1,5 @@
package com.spotify.remoteconfig.internal;
public final class AccountAttribute {
public Object value_;
}

View File

@@ -1,7 +1,7 @@
package app.revanced.extension.youtube.patches;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
import app.revanced.extension.youtube.shared.ShortsPlayerState;
@SuppressWarnings("unused")
public class BackgroundPlaybackPatch {
@@ -23,16 +23,7 @@ public class BackgroundPlaybackPatch {
// 7. Close the Short
// 8. Resume playing the regular video
// 9. Minimize the app (PIP should appear)
if (!VideoInformation.lastVideoIdIsShort()) {
return true; // Definitely is not a Short.
}
// TODO: Add better hook.
// Might be a Shorts, or might be a prior regular video on screen again after a Shorts was closed.
// This incorrectly prevents PIP if player is in WATCH_WHILE_MINIMIZED after closing a Shorts,
// But there's no way around this unless an additional hook is added to definitively detect
// the Shorts player is on screen. This use case is unusual anyways so it's not a huge concern.
return !PlayerType.getCurrent().isNoneHiddenOrMinimized();
return !ShortsPlayerState.isOpen();
}
/**

View File

@@ -1,9 +1,17 @@
package app.revanced.extension.youtube.patches;
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
import android.view.View;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Utils;
import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar;
import app.revanced.extension.youtube.shared.PlayerType;
@SuppressWarnings("unused")
public class ChangeFormFactorPatch {
@@ -41,14 +49,57 @@ public class ChangeFormFactorPatch {
@Nullable
private static final Integer FORM_FACTOR_TYPE = Settings.CHANGE_FORM_FACTOR.get().formFactorType;
private static final boolean USING_AUTOMOTIVE_TYPE = Objects.requireNonNull(
FormFactor.AUTOMOTIVE.formFactorType).equals(FORM_FACTOR_TYPE);
/**
* Injection point.
*/
public static int getFormFactor(int original) {
return FORM_FACTOR_TYPE == null
? original
: FORM_FACTOR_TYPE;
if (FORM_FACTOR_TYPE == null) return original;
if (USING_AUTOMOTIVE_TYPE) {
// Do not change if the player is opening or is opened,
// otherwise the video description cannot be opened.
PlayerType current = PlayerType.getCurrent();
if (current.isMaximizedOrFullscreen() || current == PlayerType.WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED) {
Logger.printDebug(() -> "Using original form factor for player");
return original;
}
if (!NavigationBar.isSearchBarActive()) {
// Automotive type shows error 400 when opening a channel page and using some explore tab.
// This is a bug in unpatched YouTube that occurs on actual Android Automotive devices.
// Work around the issue by using the original form factor if not in search and the
// navigation back button is present.
if (NavigationBar.isBackButtonVisible()) {
Logger.printDebug(() -> "Using original form factor, as back button is visible without search present");
return original;
}
// Do not change library tab otherwise watch history is hidden.
// Do this check last since the current navigation button is required.
if (NavigationButton.getSelectedNavigationButton() == NavigationButton.LIBRARY) {
return original;
}
}
}
return FORM_FACTOR_TYPE;
}
/**
* Injection point.
*/
public static void navigationTabCreated(NavigationButton button, View tabView) {
// On first startup of the app the navigation buttons are fetched and updated.
// If the user immediately opens the 'You' or opens a video, then the call to
// update the navigtation buttons will use the non automotive form factor
// and the explore tab is missing.
// Fixing this is not so simple because of the concurrent calls for the player and You tab.
// For now, always hide the explore tab.
if (USING_AUTOMOTIVE_TYPE && button == NavigationButton.EXPLORE) {
tabView.setVisibility(View.GONE);
}
}
}

View File

@@ -1,7 +1,7 @@
package app.revanced.extension.youtube.patches;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
import app.revanced.extension.youtube.shared.ShortsPlayerState;
@SuppressWarnings("unused")
public class DisableAutoCaptionsPatch {
@@ -14,7 +14,7 @@ public class DisableAutoCaptionsPatch {
public static boolean autoCaptionsEnabled() {
return Settings.AUTO_CAPTIONS.get()
// Do not use auto captions for Shorts.
&& !PlayerType.getCurrent().isNoneHiddenOrSlidingMinimized();
&& ShortsPlayerState.isOpen();
}
}

View File

@@ -1,8 +1,11 @@
package app.revanced.extension.youtube.patches;
import android.view.View;
import androidx.annotation.Nullable;
import app.revanced.extension.youtube.shared.PlayerType;
import app.revanced.extension.youtube.shared.ShortsPlayerState;
import app.revanced.extension.youtube.shared.VideoState;
@SuppressWarnings("unused")
@@ -24,4 +27,26 @@ public class PlayerTypeHookPatch {
VideoState.setFromString(youTubeVideoState.name());
}
/**
* Injection point.
*
* Add a listener to the shorts player overlay View.
* Triggered when a shorts player is attached or detached to Windows.
*
* @param view shorts player overlay (R.id.reel_watch_player).
*/
public static void onShortsCreate(View view) {
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(@Nullable View v) {
ShortsPlayerState.setOpen(true);
}
@Override
public void onViewDetachedFromWindow(@Nullable View v) {
ShortsPlayerState.setOpen(false);
}
});
}
}

View File

@@ -21,7 +21,6 @@ import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.ReturnYouTubeDislikeFilterPatch;
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
import app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike;
import app.revanced.extension.youtube.returnyoutubedislike.requests.ReturnYouTubeDislikeApi;
import app.revanced.extension.youtube.settings.Settings;
@@ -47,9 +46,6 @@ import app.revanced.extension.youtube.shared.PlayerType;
@SuppressWarnings("unused")
public class ReturnYouTubeDislikePatch {
public static final boolean IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER =
SpoofAppVersionPatch.isSpoofingToLessThan("18.34.00");
/**
* RYD data for the current video on screen.
*/
@@ -347,137 +343,6 @@ public class ReturnYouTubeDislikePatch {
}
}
//
// Non litho Shorts player.
//
/**
* Replacement text to use for "Dislikes" while RYD is fetching.
*/
private static final Spannable SHORTS_LOADING_SPAN = new SpannableString("-");
/**
* Dislikes TextViews used by Shorts.
*
* Multiple TextViews are loaded at once (for the prior and next videos to swipe to).
* Keep track of all of them, and later pick out the correct one based on their on screen position.
*/
private static final List<WeakReference<TextView>> shortsTextViewRefs = new ArrayList<>();
private static void clearRemovedShortsTextViews() {
shortsTextViewRefs.removeIf(ref -> ref.get() == null);
}
/**
* Injection point. Called when a Shorts dislike is updated. Always on main thread.
* Handles update asynchronously, otherwise Shorts video will be frozen while the UI thread is blocked.
*
* @return if RYD is enabled and the TextView was updated.
*/
public static boolean setShortsDislikes(@NonNull View likeDislikeView) {
try {
if (!Settings.RYD_ENABLED.get()) {
return false;
}
if (!Settings.RYD_SHORTS.get() || Settings.HIDE_SHORTS_DISLIKE_BUTTON.get()) {
// Must clear the data here, in case a new video was loaded while PlayerType
// suggested the video was not a short (can happen when spoofing to an old app version).
clearData();
return false;
}
Logger.printDebug(() -> "setShortsDislikes");
TextView textView = (TextView) likeDislikeView;
textView.setText(SHORTS_LOADING_SPAN); // Change 'Dislike' text to the loading text.
shortsTextViewRefs.add(new WeakReference<>(textView));
if (likeDislikeView.isSelected() && isShortTextViewOnScreen(textView)) {
Logger.printDebug(() -> "Shorts dislike is already selected");
ReturnYouTubeDislike videoData = currentVideoData;
if (videoData != null) videoData.setUserVote(Vote.DISLIKE);
}
// For the first short played, the Shorts dislike hook is called after the video id hook.
// But for most other times this hook is called before the video id (which is not ideal).
// Must update the TextViews here, and also after the videoId changes.
updateOnScreenShortsTextViews(false);
return true;
} catch (Exception ex) {
Logger.printException(() -> "setShortsDislikes failure", ex);
return false;
}
}
/**
* @param forceUpdate if false, then only update the 'loading text views.
* If true, update all on screen text views.
*/
private static void updateOnScreenShortsTextViews(boolean forceUpdate) {
try {
clearRemovedShortsTextViews();
if (shortsTextViewRefs.isEmpty()) {
return;
}
ReturnYouTubeDislike videoData = currentVideoData;
if (videoData == null) {
return;
}
Logger.printDebug(() -> "updateShortsTextViews");
Runnable update = () -> {
Spanned shortsDislikesSpan = videoData.getDislikeSpanForShort(SHORTS_LOADING_SPAN);
Utils.runOnMainThreadNowOrLater(() -> {
String videoId = videoData.getVideoId();
if (!videoId.equals(VideoInformation.getVideoId())) {
// User swiped to new video before fetch completed
Logger.printDebug(() -> "Ignoring stale dislikes data for short: " + videoId);
return;
}
// Update text views that appear to be visible on screen.
// Only 1 will be the actual textview for the current Short,
// but discarded and not yet garbage collected views can remain.
// So must set the dislike span on all views that match.
for (WeakReference<TextView> textViewRef : shortsTextViewRefs) {
TextView textView = textViewRef.get();
if (textView == null) {
continue;
}
if (isShortTextViewOnScreen(textView)
&& (forceUpdate || textView.getText().toString().equals(SHORTS_LOADING_SPAN.toString()))) {
Logger.printDebug(() -> "Setting Shorts TextView to: " + shortsDislikesSpan);
textView.setText(shortsDislikesSpan);
}
}
});
};
if (videoData.fetchCompleted()) {
update.run(); // Network call is completed, no need to wait on background thread.
} else {
Utils.runOnBackgroundThread(update);
}
} catch (Exception ex) {
Logger.printException(() -> "updateOnScreenShortsTextViews failure", ex);
}
}
/**
* Check if a view is within the screen bounds.
*/
private static boolean isShortTextViewOnScreen(@NonNull View view) {
final int[] location = new int[2];
view.getLocationInWindow(location);
if (location[0] <= 0 && location[1] <= 0) { // Lower bound
return false;
}
Rect windowRect = new Rect();
view.getWindowVisibleDisplayFrame(windowRect); // Upper bound
return location[0] < windowRect.width() && location[1] < windowRect.height();
}
//
// Video Id and voting hooks (all players).
//
@@ -503,8 +368,7 @@ public class ReturnYouTubeDislikePatch {
if (videoIdIsShort && (!isShortAndOpeningOrPlaying || !Settings.RYD_SHORTS.get())) {
return;
}
final boolean waitForFetchToComplete = !IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER
&& videoIdIsShort && !lastPlayerResponseWasShort;
final boolean waitForFetchToComplete = videoIdIsShort && !lastPlayerResponseWasShort;
Logger.printDebug(() -> "Prefetching RYD for video: " + videoId);
ReturnYouTubeDislike fetch = ReturnYouTubeDislike.getFetchForVideoId(videoId);
@@ -557,12 +421,6 @@ public class ReturnYouTubeDislikePatch {
data.setVideoIdIsShort(true);
}
currentVideoData = data;
// Current video id hook can be called out of order with the non litho Shorts text view hook.
// Must manually update again here.
if (isNoneHiddenOrSlidingMinimized) {
updateOnScreenShortsTextViews(true);
}
} catch (Exception ex) {
Logger.printException(() -> "newVideoLoaded failure", ex);
}

View File

@@ -74,6 +74,7 @@ public final class AdsFilter extends Filter {
"video_display_button_group_layout",
"landscape_image_wide_button_layout",
"video_display_carousel_button_group_layout",
"video_display_full_buttoned_short_dr_layout",
"compact_landscape_image_layout", // Tablet layout search results.
"text_image_no_button_layout" // Tablet layout search results.
);

View File

@@ -2,20 +2,20 @@ package app.revanced.extension.youtube.patches.components;
import androidx.annotation.Nullable;
import app.revanced.extension.youtube.patches.playback.quality.RestoreOldVideoQualityMenuPatch;
import app.revanced.extension.youtube.patches.playback.quality.AdvancedVideoQualityMenuPatch;
import app.revanced.extension.youtube.settings.Settings;
/**
* Abuse LithoFilter for {@link RestoreOldVideoQualityMenuPatch}.
* Abuse LithoFilter for {@link AdvancedVideoQualityMenuPatch}.
*/
public final class VideoQualityMenuFilterPatch extends Filter {
public final class AdvancedVideoQualityMenuFilter extends Filter {
// Must be volatile or synchronized, as litho filtering runs off main thread
// and this field is then access from the main thread.
public static volatile boolean isVideoQualityMenuVisible;
public VideoQualityMenuFilterPatch() {
public AdvancedVideoQualityMenuFilter() {
addPathCallbacks(new StringFilterGroup(
Settings.RESTORE_OLD_VIDEO_QUALITY_MENU,
Settings.ADVANCED_VIDEO_QUALITY_MENU,
"quick_quality_sheet_content.eml-js"
));
}

View File

@@ -12,10 +12,12 @@ final class CommentsFilter extends Filter {
private final StringFilterGroup commentComposer;
private final ByteArrayFilterGroup emojiPickerBufferGroup;
private final StringFilterGroup filterChipBar;
private final ByteArrayFilterGroup aiCommentsSummary;
public CommentsFilter() {
var chatSummary = new StringFilterGroup(
Settings.HIDE_COMMENTS_CHAT_SUMMARY,
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
"live_chat_summary_banner.eml"
);
@@ -58,6 +60,16 @@ final class CommentsFilter extends Filter {
"id.comment.quick_emoji.button"
);
filterChipBar = new StringFilterGroup(
Settings.HIDE_COMMENTS_AI_SUMMARY,
"filter_chip_bar.eml"
);
aiCommentsSummary = new ByteArrayFilterGroup(
null,
"yt_fill_spark_"
);
addPathCallbacks(
chatSummary,
commentsByMembers,
@@ -65,7 +77,8 @@ final class CommentsFilter extends Filter {
createAShort,
previewComment,
thanksButton,
commentComposer
commentComposer,
filterChipBar
);
}
@@ -84,6 +97,13 @@ final class CommentsFilter extends Filter {
return false;
}
if (matchedGroup == filterChipBar) {
if (aiCommentsSummary.check(protobufBufferArray).isFiltered()) {
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
}
return false;
}
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
}
}

View File

@@ -23,6 +23,11 @@ final class DescriptionComponentsFilter extends Filter {
"metadata"
);
final StringFilterGroup aiGeneratedVideoSummarySection = new StringFilterGroup(
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
"cell_expandable_metadata.eml"
);
final StringFilterGroup attributesSection = new StringFilterGroup(
Settings.HIDE_ATTRIBUTES_SECTION,
"gaming_section",
@@ -67,6 +72,7 @@ final class DescriptionComponentsFilter extends Filter {
);
addPathCallbacks(
aiGeneratedVideoSummarySection,
attributesSection,
infoCardsSection,
howThisWasMadeSection,

View File

@@ -462,6 +462,12 @@ public final class LayoutComponentsFilter extends Filter {
return true;
}
// Do not hide if the navigation back button is visible,
// otherwise the content shelves in the YouTube Movie/Courses pages is hidden.
if (NavigationBar.isBackButtonVisible()) {
return false;
}
// Check navigation button last.
// Only filter if the library tab is not selected.
// This check is important as the shelf layout is used for the library tab playlists.

View File

@@ -8,30 +8,30 @@ import android.widget.ListView;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.VideoQualityMenuFilterPatch;
import app.revanced.extension.youtube.patches.components.AdvancedVideoQualityMenuFilter;
import app.revanced.extension.youtube.settings.Settings;
/**
* This patch contains the logic to show the old video quality menu.
* This patch contains the logic to always open the advanced video quality menu.
* Two methods are required, because the quality menu is a RecyclerView in the new YouTube version
* and a ListView in the old one.
*/
@SuppressWarnings("unused")
public final class RestoreOldVideoQualityMenuPatch {
public final class AdvancedVideoQualityMenuPatch {
/**
* Injection point.
*/
public static void onFlyoutMenuCreate(RecyclerView recyclerView) {
if (!Settings.RESTORE_OLD_VIDEO_QUALITY_MENU.get()) return;
if (!Settings.ADVANCED_VIDEO_QUALITY_MENU.get()) return;
recyclerView.getViewTreeObserver().addOnDrawListener(() -> {
try {
// Check if the current view is the quality menu.
if (!VideoQualityMenuFilterPatch.isVideoQualityMenuVisible || recyclerView.getChildCount() == 0) {
if (!AdvancedVideoQualityMenuFilter.isVideoQualityMenuVisible || recyclerView.getChildCount() == 0) {
return;
}
VideoQualityMenuFilterPatch.isVideoQualityMenuVisible = false;
AdvancedVideoQualityMenuFilter.isVideoQualityMenuVisible = false;
ViewParent quickQualityViewParent = Utils.getParentView(recyclerView, 3);
if (!(quickQualityViewParent instanceof ViewGroup)) {
@@ -39,16 +39,15 @@ public final class RestoreOldVideoQualityMenuPatch {
}
View firstChild = recyclerView.getChildAt(0);
if (!(firstChild instanceof ViewGroup)) {
if (!(firstChild instanceof ViewGroup firstChildGroup)) {
return;
}
ViewGroup advancedQualityParentView = (ViewGroup) firstChild;
if (advancedQualityParentView.getChildCount() < 4) {
if (firstChildGroup.getChildCount() < 4) {
return;
}
View advancedQualityView = advancedQualityParentView.getChildAt(3);
View advancedQualityView = firstChildGroup.getChildAt(3);
if (advancedQualityView == null) {
return;
}
@@ -71,7 +70,7 @@ public final class RestoreOldVideoQualityMenuPatch {
* Used to force the creation of the advanced menu item for the Shorts quality flyout.
*/
public static boolean forceAdvancedVideoQualityMenuCreation(boolean original) {
return Settings.RESTORE_OLD_VIDEO_QUALITY_MENU.get() || original;
return Settings.ADVANCED_VIDEO_QUALITY_MENU.get() || original;
}
/**
@@ -79,8 +78,8 @@ public final class RestoreOldVideoQualityMenuPatch {
*
* Used if spoofing to an old app version, and also used for the Shorts video quality flyout.
*/
public static void showOldVideoQualityMenu(final ListView listView) {
if (!Settings.RESTORE_OLD_VIDEO_QUALITY_MENU.get()) return;
public static void showAdvancedVideoQualityMenu(ListView listView) {
if (!Settings.ADVANCED_VIDEO_QUALITY_MENU.get()) return;
listView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override

View File

@@ -12,15 +12,19 @@ import java.util.List;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BooleanSetting;
import app.revanced.extension.shared.settings.IntegerSetting;
import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.ShortsPlayerState;
@SuppressWarnings("unused")
public class RememberVideoQualityPatch {
private static final int AUTOMATIC_VIDEO_QUALITY_VALUE = -2;
private static final IntegerSetting wifiQualitySetting = Settings.VIDEO_QUALITY_DEFAULT_WIFI;
private static final IntegerSetting mobileQualitySetting = Settings.VIDEO_QUALITY_DEFAULT_MOBILE;
private static final IntegerSetting videoQualityWifi = Settings.VIDEO_QUALITY_DEFAULT_WIFI;
private static final IntegerSetting videoQualityMobile = Settings.VIDEO_QUALITY_DEFAULT_MOBILE;
private static final IntegerSetting shortsQualityWifi = Settings.SHORTS_QUALITY_DEFAULT_WIFI;
private static final IntegerSetting shortsQualityMobile = Settings.SHORTS_QUALITY_DEFAULT_MOBILE;
private static boolean qualityNeedsUpdating;
@@ -41,17 +45,29 @@ public class RememberVideoQualityPatch {
@Nullable
private static List<Integer> videoQualities;
private static boolean shouldRememberVideoQuality() {
BooleanSetting preference = ShortsPlayerState.isOpen() ?
Settings.REMEMBER_SHORTS_QUALITY_LAST_SELECTED
: Settings.REMEMBER_VIDEO_QUALITY_LAST_SELECTED;
return preference.get();
}
private static void changeDefaultQuality(int defaultQuality) {
String networkTypeMessage;
boolean useShortsPreference = ShortsPlayerState.isOpen();
if (Utils.getNetworkType() == NetworkType.MOBILE) {
mobileQualitySetting.save(defaultQuality);
if (useShortsPreference) shortsQualityMobile.save(defaultQuality);
else videoQualityMobile.save(defaultQuality);
networkTypeMessage = str("revanced_remember_video_quality_mobile");
} else {
wifiQualitySetting.save(defaultQuality);
if (useShortsPreference) shortsQualityWifi.save(defaultQuality);
else videoQualityWifi.save(defaultQuality);
networkTypeMessage = str("revanced_remember_video_quality_wifi");
}
Utils.showToastShort(
str("revanced_remember_video_quality_toast", networkTypeMessage, (defaultQuality + "p")));
Utils.showToastShort(str(
useShortsPreference ? "revanced_remember_video_quality_toast_shorts" : "revanced_remember_video_quality_toast",
networkTypeMessage, (defaultQuality + "p")
));
}
/**
@@ -62,9 +78,10 @@ public class RememberVideoQualityPatch {
*/
public static int setVideoQuality(Object[] qualities, final int originalQualityIndex, Object qInterface, String qIndexMethod) {
try {
boolean useShortsPreference = ShortsPlayerState.isOpen();
final int preferredQuality = Utils.getNetworkType() == NetworkType.MOBILE
? mobileQualitySetting.get()
: wifiQualitySetting.get();
? (useShortsPreference ? shortsQualityMobile : videoQualityMobile).get()
: (useShortsPreference ? shortsQualityWifi : videoQualityWifi).get();
if (!userChangedDefaultQuality && preferredQuality == AUTOMATIC_VIDEO_QUALITY_VALUE) {
return originalQualityIndex; // Nothing to do.
@@ -141,17 +158,17 @@ public class RememberVideoQualityPatch {
* Injection point. Old quality menu.
*/
public static void userChangedQuality(int selectedQualityIndex) {
if (!Settings.REMEMBER_VIDEO_QUALITY_LAST_SELECTED.get()) return;
userSelectedQualityIndex = selectedQualityIndex;
userChangedDefaultQuality = true;
if (shouldRememberVideoQuality()) {
userSelectedQualityIndex = selectedQualityIndex;
userChangedDefaultQuality = true;
}
}
/**
* Injection point. New quality menu.
*/
public static void userChangedQualityInNewFlyout(int selectedQuality) {
if (!Settings.REMEMBER_VIDEO_QUALITY_LAST_SELECTED.get()) return;
if (!shouldRememberVideoQuality()) return;
changeDefaultQuality(selectedQuality); // Quality is human readable resolution (ie: 1080).
}

View File

@@ -37,7 +37,6 @@ import java.util.concurrent.*;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.ThemeHelper;
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
import app.revanced.extension.youtube.returnyoutubedislike.requests.RYDVoteData;
import app.revanced.extension.youtube.returnyoutubedislike.requests.ReturnYouTubeDislikeApi;
import app.revanced.extension.youtube.settings.Settings;
@@ -87,9 +86,6 @@ public class ReturnYouTubeDislike {
*/
private static final char MIDDLE_SEPARATOR_CHARACTER = '◎'; // 'bullseye'
private static final boolean IS_SPOOFING_TO_OLD_SEPARATOR_COLOR
= SpoofAppVersionPatch.isSpoofingToLessThan("18.10.00");
/**
* Cached lookup of all video ids.
*/
@@ -184,17 +180,8 @@ public class ReturnYouTubeDislike {
* Color of the left and middle separator, based on the color of the right separator.
* It's unknown where YT gets the color from, and the values here are approximated by hand.
* Ideally, this would be the actual color YT uses at runtime.
*
* Older versions before the 'Me' library tab use a slightly different color.
* If spoofing was previously used and is now turned off,
* or an old version was recently upgraded then the old colors are sometimes still used.
*/
private static int getSeparatorColor() {
if (IS_SPOOFING_TO_OLD_SEPARATOR_COLOR) {
return ThemeHelper.isDarkTheme()
? 0x29AAAAAA // transparent dark gray
: 0xFFD9D9D9; // light gray
}
return ThemeHelper.isDarkTheme()
? 0x33FFFFFF
: 0xFFD9D9D9;

View File

@@ -3,7 +3,6 @@ package app.revanced.extension.youtube.settings;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.settings.Setting.Availability;
import static app.revanced.extension.shared.settings.Setting.migrateFromOldPreferences;
import static app.revanced.extension.shared.settings.Setting.migrateOldSettingToNew;
import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.settings.Setting.parentsAny;
@@ -21,7 +20,6 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerT
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MODERN_4;
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
import static app.revanced.extension.youtube.patches.VersionCheckPatch.IS_19_17_OR_GREATER;
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
@@ -38,7 +36,6 @@ import app.revanced.extension.shared.settings.IntegerSetting;
import app.revanced.extension.shared.settings.LongSetting;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.settings.StringSetting;
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
@@ -47,11 +44,14 @@ import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
public class Settings extends BaseSettings {
// Video
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
public static final BooleanSetting RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
public static final IntegerSetting SHORTS_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_shorts_quality_default_wifi", -2, true);
public static final IntegerSetting SHORTS_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_shorts_quality_default_mobile", -2, true);
public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE);
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
// Speed
public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true);
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE);
@@ -168,14 +168,16 @@ public class Settings extends BaseSettings {
public static final StringSetting EXTERNAL_DOWNLOADER_PACKAGE_NAME = new StringSetting("revanced_external_downloader_name",
"org.schabi.newpipe" /* NewPipe */, parentsAny(EXTERNAL_DOWNLOADER, EXTERNAL_DOWNLOADER_ACTION_BUTTON));
// Comments
public static final BooleanSetting HIDE_COMMENTS_CHAT_SUMMARY = new BooleanSetting("revanced_hide_comments_chat_summary", FALSE);
public static final BooleanSetting HIDE_COMMENTS_AI_CHAT_SUMMARY = new BooleanSetting("revanced_hide_comments_ai_chat_summary", FALSE);
public static final BooleanSetting HIDE_COMMENTS_AI_SUMMARY = new BooleanSetting("revanced_hide_comments_ai_summary", FALSE);
public static final BooleanSetting HIDE_COMMENTS_BY_MEMBERS_HEADER = new BooleanSetting("revanced_hide_comments_by_members_header", FALSE);
public static final BooleanSetting HIDE_COMMENTS_CREATE_A_SHORT_BUTTON = new BooleanSetting("revanced_hide_comments_create_a_short_button", TRUE);
public static final BooleanSetting HIDE_COMMENTS_TIMESTAMP_AND_EMOJI_BUTTONS = new BooleanSetting("revanced_hide_comments_timestamp_and_emoji_buttons", TRUE);
public static final BooleanSetting HIDE_COMMENTS_PREVIEW_COMMENT = new BooleanSetting("revanced_hide_comments_preview_comment", FALSE);
public static final BooleanSetting HIDE_COMMENTS_SECTION = new BooleanSetting("revanced_hide_comments_section", FALSE);
public static final BooleanSetting HIDE_COMMENTS_THANKS_BUTTON = new BooleanSetting("revanced_hide_comments_thanks_button", TRUE);
public static final BooleanSetting HIDE_COMMENTS_TIMESTAMP_AND_EMOJI_BUTTONS = new BooleanSetting("revanced_hide_comments_timestamp_and_emoji_buttons", TRUE);
// Description
public static final BooleanSetting HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION = new BooleanSetting("revanced_hide_ai_generated_video_summary_section", FALSE);
public static final BooleanSetting HIDE_ATTRIBUTES_SECTION = new BooleanSetting("revanced_hide_attributes_section", FALSE);
public static final BooleanSetting HIDE_CHAPTERS_SECTION = new BooleanSetting("revanced_hide_chapters_section", TRUE);
public static final BooleanSetting HIDE_HOW_THIS_WAS_MADE_SECTION = new BooleanSetting("revanced_hide_how_this_was_made_section", FALSE);
@@ -218,7 +220,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");
public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true);
public static final EnumSetting<StartPage> CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.DEFAULT, true);
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", IS_19_17_OR_GREATER ? "19.26.42" : "17.33.42", true, parent(SPOOF_APP_VERSION));
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "19.01.34", true, parent(SPOOF_APP_VERSION));
// Custom filter
public static final BooleanSetting CUSTOM_FILTER = new BooleanSetting("revanced_custom_filter", FALSE);
public static final StringSetting CUSTOM_FILTER_STRINGS = new StringSetting("revanced_custom_filter_strings", "", true, parent(CUSTOM_FILTER));
@@ -362,52 +364,54 @@ public class Settings extends BaseSettings {
public static final BooleanSetting SB_SEEN_GUIDELINES = new BooleanSetting("sb_seen_guidelines", FALSE, false, false);
public static final StringSetting SB_CATEGORY_SPONSOR = new StringSetting("sb_sponsor", SKIP_AUTOMATICALLY_ONCE.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_SPONSOR_COLOR = new StringSetting("sb_sponsor_color", "#00D400");
public static final FloatSetting SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_SELF_PROMO = new StringSetting("sb_selfpromo", MANUAL_SKIP.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_SELF_PROMO_COLOR = new StringSetting("sb_selfpromo_color", "#FFFF00");
public static final FloatSetting SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_INTERACTION = new StringSetting("sb_interaction", MANUAL_SKIP.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_INTERACTION_COLOR = new StringSetting("sb_interaction_color", "#CC00FF");
public static final FloatSetting SB_CATEGORY_INTERACTION_OPACITY = new FloatSetting("sb_interaction_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_HIGHLIGHT = new StringSetting("sb_highlight", MANUAL_SKIP.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_HIGHLIGHT_COLOR = new StringSetting("sb_highlight_color", "#FF1684");
public static final FloatSetting SB_CATEGORY_HIGHLIGHT_OPACITY = new FloatSetting("sb_highlight_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_INTRO = new StringSetting("sb_intro", MANUAL_SKIP.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_INTRO_COLOR = new StringSetting("sb_intro_color", "#00FFFF");
public static final FloatSetting SB_CATEGORY_INTRO_OPACITY = new FloatSetting("sb_intro_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_OUTRO = new StringSetting("sb_outro", MANUAL_SKIP.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_OUTRO_COLOR = new StringSetting("sb_outro_color", "#0202ED");
public static final FloatSetting SB_CATEGORY_OUTRO_OPACITY = new FloatSetting("sb_outro_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_PREVIEW = new StringSetting("sb_preview", IGNORE.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_PREVIEW_COLOR = new StringSetting("sb_preview_color", "#008FD6");
public static final FloatSetting SB_CATEGORY_PREVIEW_OPACITY = new FloatSetting("sb_preview_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_FILLER = new StringSetting("sb_filler", IGNORE.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_FILLER_COLOR = new StringSetting("sb_filler_color", "#7300FF");
public static final FloatSetting SB_CATEGORY_FILLER_OPACITY = new FloatSetting("sb_filler_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC = new StringSetting("sb_music_offtopic", MANUAL_SKIP.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC_COLOR = new StringSetting("sb_music_offtopic_color", "#FF9900");
public static final FloatSetting SB_CATEGORY_MUSIC_OFFTOPIC_OPACITY = new FloatSetting("sb_music_offtopic_opacity", 0.8f);
public static final StringSetting SB_CATEGORY_UNSUBMITTED = new StringSetting("sb_unsubmitted", SKIP_AUTOMATICALLY.reVancedKeyValue);
public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFF");
public static final FloatSetting SB_CATEGORY_UNSUBMITTED_OPACITY = new FloatSetting("sb_unsubmitted_opacity", 1.0f);
// Deprecated migrations
private static final StringSetting DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING = new StringSetting("uuid", ""); // Delete sometime in 2024
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true);
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE);
private static final IntegerSetting DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127);
private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033");
private static final BooleanSetting DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE);
private static final BooleanSetting DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
static {
// region Migration
// Do _not_ delete this SB private user id migration property until sometime in early 2025.
// This is the only setting that cannot be reconfigured if lost,
// and more time should be given for users who rarely upgrade.
SharedPrefCategory sbPrefs = new SharedPrefCategory("sponsor-block");
// Remove the "sb_" prefix, as old settings are saved without it.
String key = DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING.key.substring(3);
migrateFromOldPreferences(sbPrefs, DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING, key);
migrateOldSettingToNew(DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING, SB_PRIVATE_USER_ID);
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS);
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER);
migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO);
migrateOldSettingToNew(DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU, ADVANCED_VIDEO_QUALITY_MENU);
// Migrate renamed enum.
//noinspection deprecation
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {
@@ -443,6 +447,12 @@ public class Settings extends BaseSettings {
DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.resetToDefault();
}
// Old spoof versions that no longer work.
if (SPOOF_APP_VERSION_TARGET.get().compareTo(SPOOF_APP_VERSION_TARGET.defaultValue) < 0) {
Logger.printInfo(() -> "Resetting spoof app version target");
SPOOF_APP_VERSION_TARGET.resetToDefault();
}
// endregion
// region SB import/export callbacks

View File

@@ -18,7 +18,6 @@ import android.widget.TextView;
import android.widget.Toolbar;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import app.revanced.extension.shared.Logger;
@@ -74,7 +73,8 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
}
}
Collections.sort(pairsToSort, (pair1, pair2) -> pair1.first.compareToIgnoreCase(pair2.first));
pairsToSort.sort((pair1, pair2)
-> pair1.first.compareToIgnoreCase(pair2.first));
CharSequence[] sortedEntries = new CharSequence[entrySize];
CharSequence[] sortedEntryValues = new CharSequence[entrySize];
@@ -109,6 +109,7 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
CustomPlaybackSpeedPatch.initializeListPreference(playbackPreference);
}
sortPreferenceListMenu(Settings.CHANGE_START_PAGE);
sortPreferenceListMenu(Settings.SPOOF_VIDEO_STREAMS_LANGUAGE);
sortPreferenceListMenu(BaseSettings.REVANCED_LANGUAGE);
} catch (Exception ex) {
@@ -137,11 +138,13 @@ public class ReVancedPreferenceFragment extends AbstractPreferenceFragment {
.findViewById(android.R.id.content)
.getParent();
// Fix required for Android 15 and YT 19.45+
// 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());
v.setPadding(0, statusInsets.top, 0, 0);
Insets navInsets = insets.getInsets(WindowInsets.Type.navigationBars());
v.setPadding(0, statusInsets.top, 0, navInsets.bottom);
return insets;
});
}

View File

@@ -14,6 +14,7 @@ import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch;
@@ -85,9 +86,7 @@ public class ReturnYouTubeDislikePreferenceFragment extends PreferenceFragment {
shortsPreference = new SwitchPreference(context);
shortsPreference.setChecked(Settings.RYD_SHORTS.get());
shortsPreference.setTitle(str("revanced_ryd_shorts_title"));
String shortsSummary = ReturnYouTubeDislikePatch.IS_SPOOFING_TO_NON_LITHO_SHORTS_PLAYER
? str("revanced_ryd_shorts_summary_on")
: str("revanced_ryd_shorts_summary_on_disclaimer");
String shortsSummary = str("revanced_ryd_shorts_summary_on_disclaimer");
shortsPreference.setSummaryOn(shortsSummary);
shortsPreference.setSummaryOff(str("revanced_ryd_shorts_summary_off"));
shortsPreference.setOnPreferenceChangeListener((pref, newValue) -> {
@@ -237,6 +236,8 @@ public class ReturnYouTubeDislikePreferenceFragment extends PreferenceFragment {
"revanced_ryd_statistics_getNumberOfRateLimitRequestsEncountered_non_zero_summary"));
preferenceScreen.addPreference(statisticPreference);
}
Utils.setPreferenceTitlesToMultiLineIfNeeded(preferenceScreen);
} catch (Exception ex) {
Logger.printException(() -> "onCreate failure", ex);
}

View File

@@ -17,6 +17,7 @@ import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.settings.preference.ResettableEditTextPreference;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController;
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
@@ -44,8 +45,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment {
private SwitchPreference showTimeWithoutSegments;
private SwitchPreference toastOnConnectionError;
private EditTextPreference newSegmentStep;
private EditTextPreference minSegmentDuration;
private ResettableEditTextPreference newSegmentStep;
private ResettableEditTextPreference minSegmentDuration;
private EditTextPreference privateUserId;
private EditTextPreference importExport;
private Preference apiUrl;
@@ -159,6 +160,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment {
addAboutCategory(context, preferenceScreen);
Utils.setPreferenceTitlesToMultiLineIfNeeded(preferenceScreen);
updateUI();
} catch (Exception ex) {
Logger.printException(() -> "onCreate failure", ex);
@@ -268,7 +271,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment {
return true;
});
newSegmentStep = new EditTextPreference(context);
newSegmentStep = new ResettableEditTextPreference(context);
newSegmentStep.setSetting(Settings.SB_CREATE_NEW_SEGMENT_STEP);
newSegmentStep.setTitle(str("revanced_sb_general_adjusting"));
newSegmentStep.setSummary(str("revanced_sb_general_adjusting_sum"));
newSegmentStep.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER);
@@ -326,7 +330,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment {
});
category.addPreference(trackSkips);
minSegmentDuration = new EditTextPreference(context);
minSegmentDuration = new ResettableEditTextPreference(context);
minSegmentDuration.setSetting(Settings.SB_SEGMENT_MIN_DURATION);
minSegmentDuration.setTitle(str("revanced_sb_general_min_duration"));
minSegmentDuration.setSummary(str("revanced_sb_general_min_duration_sum"));
minSegmentDuration.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
@@ -345,7 +350,15 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment {
});
category.addPreference(minSegmentDuration);
privateUserId = new EditTextPreference(context);
privateUserId = new EditTextPreference(context) {
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
Utils.setEditTextDialogTheme(builder);
builder.setNeutralButton(str("revanced_sb_settings_copy"), (dialog, which) -> {
Utils.setClipboard(getEditText().getText().toString());
});
}
};
privateUserId.setTitle(str("revanced_sb_general_uuid"));
privateUserId.setSummary(str("revanced_sb_general_uuid_sum"));
privateUserId.setOnPreferenceChangeListener((preference1, newValue) -> {
@@ -504,7 +517,7 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment {
if (stats.totalSegmentCountIncludingIgnored > 0) {
// If user has not created any segments, there's no reason to set a username.
EditTextPreference preference = new EditTextPreference(context);
EditTextPreference preference = new ResettableEditTextPreference(context);
statsCategory.addPreference(preference);
String userName = stats.userName;
preference.setTitle(fromHtml(str("revanced_sb_stats_username", userName)));

View File

@@ -73,6 +73,7 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
if (currentClientType == clientType) {
return;
}
currentClientType = clientType;
Logger.printDebug(() -> "Updating spoof stream side effects preference");
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());

View File

@@ -3,7 +3,9 @@ package app.revanced.extension.youtube.shared;
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton.CREATE;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -24,12 +26,22 @@ import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public final class NavigationBar {
/**
* Interface to call obfuscated methods in AppCompat Toolbar class.
*/
public interface AppCompatToolbarPatchInterface {
Drawable patch_getNavigationIcon();
}
//
// Search bar
// Search and toolbar.
//
private static volatile WeakReference<View> searchBarResultsRef = new WeakReference<>(null);
private static volatile WeakReference<AppCompatToolbarPatchInterface> toolbarResultsRef
= new WeakReference<>(null);
/**
* Injection point.
*/
@@ -37,6 +49,22 @@ public final class NavigationBar {
searchBarResultsRef = new WeakReference<>(searchbarResults);
}
/**
* Injection point.
*/
public static void setToolbar(FrameLayout layout) {
AppCompatToolbarPatchInterface toolbar = Utils.getChildView(layout, false, (view) ->
view instanceof AppCompatToolbarPatchInterface
);
if (toolbar == null) {
Logger.printException(() -> "Could not find navigation toolbar");
return;
}
toolbarResultsRef = new WeakReference<>(toolbar);
}
/**
* @return If the search bar is on screen. This includes if the player
* is on screen and the search results are behind the player (and not visible).
@@ -47,8 +75,13 @@ public final class NavigationBar {
return searchbarResults != null && searchbarResults.getParent() != null;
}
public static boolean isBackButtonVisible() {
AppCompatToolbarPatchInterface toolbar = toolbarResultsRef.get();
return toolbar != null && toolbar.patch_getNavigationIcon() != null;
}
//
// Navigation bar buttons
// Navigation bar buttons.
//
/**

View File

@@ -5,7 +5,7 @@ import app.revanced.extension.youtube.Event
import app.revanced.extension.youtube.patches.VideoInformation
/**
* Main player type.
* Regular player type.
*/
enum class PlayerType {
/**
@@ -90,8 +90,6 @@ enum class PlayerType {
* Does not include the first moment after a short is opened when a regular video is minimized on screen,
* or while watching a short with a regular video present on a spoofed 16.x version of YouTube.
* To include those situations instead use [isNoneHiddenOrMinimized].
*
* @see VideoInformation
*/
fun isNoneOrHidden(): Boolean {
return this == NONE || this == HIDDEN
@@ -107,8 +105,11 @@ enum class PlayerType {
* when spoofing to an old version this will return false even
* though a Short is being opened or is on screen (see [isNoneHiddenOrMinimized]).
*
* Instead of this method, consider using {@link ShortsPlayerState}
* which may work better for some situations.
*
* @return If nothing, a Short, or a regular video is sliding off screen to a dismissed or hidden state.
* @see VideoInformation
* @see ShortsPlayerState
*/
fun isNoneHiddenOrSlidingMinimized(): Boolean {
return isNoneOrHidden() || this == WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED
@@ -125,9 +126,12 @@ enum class PlayerType {
* Typically used to detect if a Short is playing when the player cannot be in a minimized state,
* such as the user interacting with a button or element of the player.
*
* Instead of this method, consider using {@link ShortsPlayerState}
* which may work better for some situations.
*
* @return If nothing, a Short, a regular video is sliding off screen to a dismissed or hidden state,
* a regular video is minimized (and a new video is not being opened).
* @see VideoInformation
* @see ShortsPlayerState
*/
fun isNoneHiddenOrMinimized(): Boolean {
return isNoneHiddenOrSlidingMinimized() || this == WATCH_WHILE_MINIMIZED

View File

@@ -0,0 +1,38 @@
package app.revanced.extension.youtube.shared
import app.revanced.extension.shared.Logger
import app.revanced.extension.youtube.Event
/**
* Shorts player state.
*/
class ShortsPlayerState {
companion object {
@JvmStatic
fun setOpen(open: Boolean) {
if (isOpen != open) {
Logger.printDebug { "ShortsPlayerState open changed to: $isOpen" }
isOpen = open
onChange(open)
}
}
@Volatile
private var isOpen = false
/**
* Shorts player state change listener.
*/
@JvmStatic
val onChange = Event<Boolean>()
/**
* If the Shorts player is currently open.
*/
@JvmStatic
fun isOpen(): Boolean {
return isOpen
}
}
}

View File

@@ -136,7 +136,7 @@ public class SponsorBlockSettings {
for (SegmentCategory category : categories) {
JSONObject categoryObject = new JSONObject();
String categoryKey = category.keyValue;
categoryObject.put("color", category.colorString());
categoryObject.put("color", category.getColorString());
barTypesObject.put(categoryKey, categoryObject);
if (category.behaviour != CategoryBehaviour.IGNORE) {

View File

@@ -5,7 +5,12 @@ import static app.revanced.extension.shared.StringRef.str;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.text.Html;
import android.graphics.Color;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.widget.EditText;
import androidx.annotation.NonNull;
@@ -33,7 +38,7 @@ import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockViewController
* Not thread safe. All fields/methods must be accessed from the main thread.
*/
public class SponsorBlockUtils {
private static final String LOCKED_COLOR = "#FFC83D";
private static final int LOCKED_COLOR = Color.parseColor("#FFC83D");
private static final String MANUAL_EDIT_TIME_TEXT_HINT = "hh:mm:ss.sss";
private static final Pattern manualEditTimePattern
= Pattern.compile("((\\d{1,2}):)?(\\d{1,2}):(\\d{2})(\\.(\\d{1,3}))?");
@@ -160,32 +165,34 @@ public class SponsorBlockUtils {
SegmentVote[] voteOptions = (segment.category == SegmentCategory.HIGHLIGHT)
? SegmentVote.voteTypesWithoutCategoryChange // highlight segments cannot change category
: SegmentVote.values();
CharSequence[] items = new CharSequence[voteOptions.length];
final int voteOptionsLength = voteOptions.length;
final boolean userIsVip = Settings.SB_USER_IS_VIP.get();
CharSequence[] items = new CharSequence[voteOptionsLength];
for (int i = 0; i < voteOptions.length; i++) {
for (int i = 0; i < voteOptionsLength; i++) {
SegmentVote voteOption = voteOptions[i];
String title = voteOption.title.toString();
if (Settings.SB_USER_IS_VIP.get() && segment.isLocked && voteOption.shouldHighlight) {
items[i] = Html.fromHtml(String.format("<font color=\"%s\">%s</font>", LOCKED_COLOR, title));
} else {
items[i] = title;
CharSequence title = voteOption.title.toString();
if (userIsVip && segment.isLocked && voteOption.highlightIfVipAndVideoIsLocked) {
SpannableString coloredTitle = new SpannableString(title);
coloredTitle.setSpan(new ForegroundColorSpan(LOCKED_COLOR),
0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
title = coloredTitle;
}
items[i] = title;
}
new AlertDialog.Builder(context)
.setItems(items, (dialog1, which1) -> {
SegmentVote voteOption = voteOptions[which1];
switch (voteOption) {
case UPVOTE:
case DOWNVOTE:
SBRequester.voteForSegmentOnBackgroundThread(segment, voteOption);
break;
case CATEGORY_CHANGE:
onNewCategorySelect(segment, context);
break;
}
})
.show();
new AlertDialog.Builder(context).setItems(items, (dialog1, which1) -> {
SegmentVote voteOption = voteOptions[which1];
switch (voteOption) {
case UPVOTE:
case DOWNVOTE:
SBRequester.voteForSegmentOnBackgroundThread(segment, voteOption);
break;
case CATEGORY_CHANGE:
onNewCategorySelect(segment, context);
break;
}
}).show();
} catch (Exception ex) {
Logger.printException(() -> "segmentVoteClickListener failure", ex);
}
@@ -282,7 +289,6 @@ public class SponsorBlockUtils {
return;
}
final int numberOfSegments = segments.length;
CharSequence[] titles = new CharSequence[numberOfSegments];
for (int i = 0; i < numberOfSegments; i++) {
@@ -290,22 +296,33 @@ public class SponsorBlockUtils {
if (segment.category == SegmentCategory.UNSUBMITTED) {
continue;
}
StringBuilder htmlBuilder = new StringBuilder();
htmlBuilder.append(String.format("<b><font color=\"#%06X\">âŦ¤</font> %s<br>",
segment.category.color, segment.category.title));
htmlBuilder.append(formatSegmentTime(segment.start));
if (segment.category != SegmentCategory.HIGHLIGHT) {
htmlBuilder.append(" to ").append(formatSegmentTime(segment.end));
SpannableStringBuilder spannableBuilder = new SpannableStringBuilder();
spannableBuilder.append(segment.category.getTitleWithColorDot());
spannableBuilder.append('\n');
String startTime = formatSegmentTime(segment.start);
if (segment.category == SegmentCategory.HIGHLIGHT) {
spannableBuilder.append(startTime);
} else {
String toFromString = str("revanced_sb_vote_segment_time_to_from",
startTime, formatSegmentTime(segment.end));
spannableBuilder.append(toFromString);
}
htmlBuilder.append("</b>");
if (i + 1 != numberOfSegments) // prevents trailing new line after last segment
htmlBuilder.append("<br>");
titles[i] = Html.fromHtml(htmlBuilder.toString());
if (i + 1 != numberOfSegments) {
// prevents trailing new line after last segment
spannableBuilder.append('\n');
}
spannableBuilder.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
0, spannableBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
titles[i] = spannableBuilder;
}
new AlertDialog.Builder(context)
.setItems(titles, segmentVoteClickListener)
.show();
new AlertDialog.Builder(context).setItems(titles, segmentVoteClickListener).show();
} catch (Exception ex) {
Logger.printException(() -> "onVotingClicked failure", ex);
}

View File

@@ -1,13 +1,14 @@
package app.revanced.extension.youtube.sponsorblock.objects;
import static app.revanced.extension.youtube.settings.Settings.*;
import static app.revanced.extension.shared.StringRef.sf;
import static app.revanced.extension.youtube.settings.Settings.*;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.Html;
import android.text.Spanned;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -15,43 +16,45 @@ import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.StringSetting;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.StringRef;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.FloatSetting;
import app.revanced.extension.shared.settings.StringSetting;
import app.revanced.extension.youtube.settings.Settings;
public enum SegmentCategory {
SPONSOR("sponsor", sf("revanced_sb_segments_sponsor"), sf("revanced_sb_segments_sponsor_sum"), sf("revanced_sb_skip_button_sponsor"), sf("revanced_sb_skipped_sponsor"),
SB_CATEGORY_SPONSOR, SB_CATEGORY_SPONSOR_COLOR),
SB_CATEGORY_SPONSOR, SB_CATEGORY_SPONSOR_COLOR, SB_CATEGORY_SPONSOR_OPACITY),
SELF_PROMO("selfpromo", sf("revanced_sb_segments_selfpromo"), sf("revanced_sb_segments_selfpromo_sum"), sf("revanced_sb_skip_button_selfpromo"), sf("revanced_sb_skipped_selfpromo"),
SB_CATEGORY_SELF_PROMO, SB_CATEGORY_SELF_PROMO_COLOR),
SB_CATEGORY_SELF_PROMO, SB_CATEGORY_SELF_PROMO_COLOR, SB_CATEGORY_SELF_PROMO_OPACITY),
INTERACTION("interaction", sf("revanced_sb_segments_interaction"), sf("revanced_sb_segments_interaction_sum"), sf("revanced_sb_skip_button_interaction"), sf("revanced_sb_skipped_interaction"),
SB_CATEGORY_INTERACTION, SB_CATEGORY_INTERACTION_COLOR),
SB_CATEGORY_INTERACTION, SB_CATEGORY_INTERACTION_COLOR, SB_CATEGORY_INTERACTION_OPACITY),
/**
* Unique category that is treated differently than the rest.
*/
HIGHLIGHT("poi_highlight", sf("revanced_sb_segments_highlight"), sf("revanced_sb_segments_highlight_sum"), sf("revanced_sb_skip_button_highlight"), sf("revanced_sb_skipped_highlight"),
SB_CATEGORY_HIGHLIGHT, SB_CATEGORY_HIGHLIGHT_COLOR),
SB_CATEGORY_HIGHLIGHT, SB_CATEGORY_HIGHLIGHT_COLOR, SB_CATEGORY_HIGHLIGHT_OPACITY),
INTRO("intro", sf("revanced_sb_segments_intro"), sf("revanced_sb_segments_intro_sum"),
sf("revanced_sb_skip_button_intro_beginning"), sf("revanced_sb_skip_button_intro_middle"), sf("revanced_sb_skip_button_intro_end"),
sf("revanced_sb_skipped_intro_beginning"), sf("revanced_sb_skipped_intro_middle"), sf("revanced_sb_skipped_intro_end"),
SB_CATEGORY_INTRO, SB_CATEGORY_INTRO_COLOR),
SB_CATEGORY_INTRO, SB_CATEGORY_INTRO_COLOR, SB_CATEGORY_INTRO_OPACITY),
OUTRO("outro", sf("revanced_sb_segments_outro"), sf("revanced_sb_segments_outro_sum"), sf("revanced_sb_skip_button_outro"), sf("revanced_sb_skipped_outro"),
SB_CATEGORY_OUTRO, SB_CATEGORY_OUTRO_COLOR),
SB_CATEGORY_OUTRO, SB_CATEGORY_OUTRO_COLOR, SB_CATEGORY_OUTRO_OPACITY),
PREVIEW("preview", sf("revanced_sb_segments_preview"), sf("revanced_sb_segments_preview_sum"),
sf("revanced_sb_skip_button_preview_beginning"), sf("revanced_sb_skip_button_preview_middle"), sf("revanced_sb_skip_button_preview_end"),
sf("revanced_sb_skipped_preview_beginning"), sf("revanced_sb_skipped_preview_middle"), sf("revanced_sb_skipped_preview_end"),
SB_CATEGORY_PREVIEW, SB_CATEGORY_PREVIEW_COLOR),
SB_CATEGORY_PREVIEW, SB_CATEGORY_PREVIEW_COLOR, SB_CATEGORY_PREVIEW_OPACITY),
FILLER("filler", sf("revanced_sb_segments_filler"), sf("revanced_sb_segments_filler_sum"), sf("revanced_sb_skip_button_filler"), sf("revanced_sb_skipped_filler"),
SB_CATEGORY_FILLER, SB_CATEGORY_FILLER_COLOR),
SB_CATEGORY_FILLER, SB_CATEGORY_FILLER_COLOR, SB_CATEGORY_FILLER_OPACITY),
MUSIC_OFFTOPIC("music_offtopic", sf("revanced_sb_segments_nomusic"), sf("revanced_sb_segments_nomusic_sum"), sf("revanced_sb_skip_button_nomusic"), sf("revanced_sb_skipped_nomusic"),
SB_CATEGORY_MUSIC_OFFTOPIC, SB_CATEGORY_MUSIC_OFFTOPIC_COLOR),
SB_CATEGORY_MUSIC_OFFTOPIC, SB_CATEGORY_MUSIC_OFFTOPIC_COLOR, SB_CATEGORY_MUSIC_OFFTOPIC_OPACITY),
UNSUBMITTED("unsubmitted", StringRef.empty, StringRef.empty, sf("revanced_sb_skip_button_unsubmitted"), sf("revanced_sb_skipped_unsubmitted"),
SB_CATEGORY_UNSUBMITTED, SB_CATEGORY_UNSUBMITTED_COLOR),;
SB_CATEGORY_UNSUBMITTED, SB_CATEGORY_UNSUBMITTED_COLOR, SB_CATEGORY_UNSUBMITTED_OPACITY);
private static final StringRef skipSponsorTextCompact = sf("revanced_sb_skip_button_compact");
private static final StringRef skipSponsorTextCompactHighlight = sf("revanced_sb_skip_button_compact_highlight");
@@ -90,12 +93,10 @@ public enum SegmentCategory {
mValuesMap.put(value.keyValue, value);
}
@NonNull
public static SegmentCategory[] categoriesWithoutUnsubmitted() {
return categoriesWithoutUnsubmitted;
}
@NonNull
public static SegmentCategory[] categoriesWithoutHighlights() {
return categoriesWithoutHighlights;
}
@@ -106,7 +107,7 @@ public enum SegmentCategory {
}
/**
* Must be called if behavior of any category is changed
* Must be called if behavior of any category is changed.
*/
public static void updateEnabledCategories() {
Utils.verifyOnMainThread();
@@ -133,32 +134,33 @@ public enum SegmentCategory {
updateEnabledCategories();
}
@NonNull
public final String keyValue;
@NonNull
public final StringSetting behaviorSetting;
@NonNull
private final StringSetting colorSetting;
public static int applyOpacityToColor(int color, float opacity) {
if (opacity < 0 || opacity > 1.0f) {
throw new IllegalArgumentException("Invalid opacity: " + opacity);
}
final int opacityInt = (int) (255 * opacity);
return (color & 0x00FFFFFF) | (opacityInt << 24);
}
public final String keyValue;
public final StringSetting behaviorSetting; // TODO: Replace with EnumSetting.
private final StringSetting colorSetting;
private final FloatSetting opacitySetting;
@NonNull
public final StringRef title;
@NonNull
public final StringRef description;
/**
* Skip button text, if the skip occurs in the first quarter of the video
*/
@NonNull
public final StringRef skipButtonTextBeginning;
/**
* Skip button text, if the skip occurs in the middle half of the video
*/
@NonNull
public final StringRef skipButtonTextMiddle;
/**
* Skip button text, if the skip occurs in the last quarter of the video
*/
@NonNull
public final StringRef skipButtonTextEnd;
/**
* Skipped segment toast, if the skip occurred in the first quarter of the video
@@ -179,10 +181,7 @@ public enum SegmentCategory {
@NonNull
public final Paint paint;
/**
* Value must be changed using {@link #setColor(String)}.
*/
public int color;
private int color;
/**
* Value must be changed using {@link #setBehaviour(CategoryBehaviour)}.
@@ -194,17 +193,20 @@ public enum SegmentCategory {
SegmentCategory(String keyValue, StringRef title, StringRef description,
StringRef skipButtonText,
StringRef skippedToastText,
StringSetting behavior, StringSetting color) {
StringSetting behavior,
StringSetting color, FloatSetting opacity) {
this(keyValue, title, description,
skipButtonText, skipButtonText, skipButtonText,
skippedToastText, skippedToastText, skippedToastText,
behavior, color);
behavior,
color, opacity);
}
SegmentCategory(String keyValue, StringRef title, StringRef description,
StringRef skipButtonTextBeginning, StringRef skipButtonTextMiddle, StringRef skipButtonTextEnd,
StringRef skippedToastBeginning, StringRef skippedToastMiddle, StringRef skippedToastEnd,
StringSetting behavior, StringSetting color) {
StringSetting behavior,
StringSetting color, FloatSetting opacity) {
this.keyValue = Objects.requireNonNull(keyValue);
this.title = Objects.requireNonNull(title);
this.description = Objects.requireNonNull(description);
@@ -216,6 +218,7 @@ public enum SegmentCategory {
this.skippedToastEnd = Objects.requireNonNull(skippedToastEnd);
this.behaviorSetting = Objects.requireNonNull(behavior);
this.colorSetting = Objects.requireNonNull(color);
this.opacitySetting = Objects.requireNonNull(opacity);
this.paint = new Paint();
loadFromSettings();
}
@@ -232,11 +235,14 @@ public enum SegmentCategory {
this.behaviour = savedBehavior;
String colorString = colorSetting.get();
final float opacity = opacitySetting.get();
try {
setColor(colorString);
setOpacity(opacity);
} catch (Exception ex) {
Logger.printException(() -> "Invalid color: " + colorString, ex);
Logger.printException(() -> "Invalid color: " + colorString + " opacity: " + opacity, ex);
colorSetting.resetToDefault();
opacitySetting.resetToDefault();
loadFromSettings();
}
}
@@ -245,45 +251,78 @@ public enum SegmentCategory {
this.behaviour = Objects.requireNonNull(behaviour);
this.behaviorSetting.save(behaviour.reVancedKeyValue);
}
/**
* @return HTML color format string
*/
@NonNull
public String colorString() {
return String.format("#%06X", color);
}
public void setColor(@NonNull String colorString) throws IllegalArgumentException {
final int color = Color.parseColor(colorString) & 0xFFFFFF;
this.color = color;
private void updateColor() {
color = applyOpacityToColor(color, opacitySetting.get());
paint.setColor(color);
paint.setAlpha(255);
colorSetting.save(colorString); // Save after parsing.
}
public void resetColor() {
/**
* @param opacity Segment color opacity between [0, 1].
*/
public void setOpacity(float opacity) throws IllegalArgumentException {
if (opacity < 0 || opacity > 1) {
throw new IllegalArgumentException("Invalid opacity: " + opacity);
}
opacitySetting.save(opacity);
updateColor();
}
public float getOpacity() {
return opacitySetting.get();
}
public void resetColorAndOpacity() {
setColor(colorSetting.defaultValue);
setOpacity(opacitySetting.defaultValue);
}
@NonNull
private static String getCategoryColorDotHTML(int color) {
color &= 0xFFFFFF;
return String.format("<font color=\"#%06X\">âŦ¤</font>", color);
/**
* @param colorString Segment color with #RRGGBB format.
*/
public void setColor(String colorString) throws IllegalArgumentException {
color = Color.parseColor(colorString);
colorSetting.save(colorString);
updateColor();
}
@NonNull
public static Spanned getCategoryColorDot(int color) {
return Html.fromHtml(getCategoryColorDotHTML(color));
/**
* @return Integer color of #RRGGBB format.
*/
public int getColorNoOpacity() {
return color & 0x00FFFFFF;
}
@NonNull
public Spanned getCategoryColorDot() {
/**
* @return Hex color string of #RRGGBB format with no opacity level.
*/
public String getColorString() {
return String.format(Locale.US, "#%06X", getColorNoOpacity());
}
private static SpannableString getCategoryColorDotSpan(String text, int color) {
SpannableString dotSpan = new SpannableString('âŦ¤' + text);
dotSpan.setSpan(new ForegroundColorSpan(color), 0, 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return dotSpan;
}
public static SpannableString getCategoryColorDot(int color) {
return getCategoryColorDotSpan("", color);
}
public SpannableString getCategoryColorDot() {
return getCategoryColorDot(color);
}
@NonNull
public Spanned getTitleWithColorDot() {
return Html.fromHtml(getCategoryColorDotHTML(color) + " " + title);
public SpannableString getTitleWithColorDot(int categoryColor) {
return getCategoryColorDotSpan(" " + title, categoryColor);
}
public SpannableString getTitleWithColorDot() {
return getTitleWithColorDot(color);
}
/**
@@ -291,7 +330,6 @@ public enum SegmentCategory {
* @param videoLength length of the video
* @return the skip button text
*/
@NonNull
StringRef getSkipButtonText(long segmentStartTime, long videoLength) {
if (Settings.SB_COMPACT_SKIP_BUTTON.get()) {
return (this == SegmentCategory.HIGHLIGHT)
@@ -300,7 +338,7 @@ public enum SegmentCategory {
}
if (videoLength == 0) {
return skipButtonTextBeginning; // video is still loading. Assume it's the beginning
return skipButtonTextBeginning; // Video is still loading. Assume it's the beginning.
}
final float position = segmentStartTime / (float) videoLength;
if (position < 0.25f) {
@@ -316,10 +354,9 @@ public enum SegmentCategory {
* @param videoLength length of the video
* @return 'skipped segment' toast message
*/
@NonNull
StringRef getSkippedToastText(long segmentStartTime, long videoLength) {
if (videoLength == 0) {
return skippedToastBeginning; // video is still loading. Assume it's the beginning
return skippedToastBeginning; // Video is still loading. Assume it's the beginning.
}
final float position = segmentStartTime / (float) videoLength;
if (position < 0.25f) {

View File

@@ -1,6 +1,7 @@
package app.revanced.extension.youtube.sponsorblock.objects;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.youtube.sponsorblock.objects.SegmentCategory.applyOpacityToColor;
import android.app.AlertDialog;
import android.content.Context;
@@ -11,11 +12,10 @@ import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.GridLayout;
import android.widget.TextView;
import java.util.Locale;
import java.util.Objects;
import app.revanced.extension.shared.Logger;
@@ -24,27 +24,38 @@ import app.revanced.extension.shared.Utils;
@SuppressWarnings("deprecation")
public class SegmentCategoryListPreference extends ListPreference {
private final SegmentCategory category;
private EditText mEditText;
private int mClickedDialogEntryIndex;
private TextView colorDotView;
private EditText colorEditText;
private EditText opacityEditText;
/**
* #RRGGBB
*/
private int categoryColor;
/**
* [0, 1]
*/
private float categoryOpacity;
private int selectedDialogEntryIndex;
public SegmentCategoryListPreference(Context context, SegmentCategory category) {
super(context);
final boolean isHighlightCategory = category == SegmentCategory.HIGHLIGHT;
this.category = Objects.requireNonNull(category);
// Edit: Using preferences to sync together multiple pieces
// of code together is messy and should be rethought.
// of code is messy and should be rethought.
setKey(category.behaviorSetting.key);
setDefaultValue(category.behaviorSetting.defaultValue);
final boolean isHighlightCategory = category == SegmentCategory.HIGHLIGHT;
setEntries(isHighlightCategory
? CategoryBehaviour.getBehaviorDescriptionsWithoutSkipOnce()
: CategoryBehaviour.getBehaviorDescriptions());
setEntryValues(isHighlightCategory
? CategoryBehaviour.getBehaviorKeyValuesWithoutSkipOnce()
: CategoryBehaviour.getBehaviorKeyValues());
setSummary(category.description.toString());
updateTitle();
updateTitleFromCategory();
}
@Override
@@ -52,26 +63,40 @@ public class SegmentCategoryListPreference extends ListPreference {
try {
Utils.setEditTextDialogTheme(builder);
categoryColor = category.getColorNoOpacity();
categoryOpacity = category.getOpacity();
Context context = builder.getContext();
TableLayout table = new TableLayout(context);
table.setOrientation(LinearLayout.HORIZONTAL);
table.setPadding(70, 0, 150, 0);
TableRow row = new TableRow(context);
GridLayout gridLayout = new GridLayout(context);
gridLayout.setPadding(70, 0, 150, 0); // Padding for the entire layout.
gridLayout.setColumnCount(3);
gridLayout.setRowCount(2);
GridLayout.LayoutParams gridParams = new GridLayout.LayoutParams();
gridParams.rowSpec = GridLayout.spec(0); // First row.
gridParams.columnSpec = GridLayout.spec(0); // First column.
TextView colorTextLabel = new TextView(context);
colorTextLabel.setText(str("revanced_sb_color_dot_label"));
row.addView(colorTextLabel);
colorTextLabel.setLayoutParams(gridParams);
gridLayout.addView(colorTextLabel);
TextView colorDotView = new TextView(context);
colorDotView.setText(category.getCategoryColorDot());
colorDotView.setPadding(30, 0, 30, 0);
row.addView(colorDotView);
gridParams = new GridLayout.LayoutParams();
gridParams.rowSpec = GridLayout.spec(0); // First row.
gridParams.columnSpec = GridLayout.spec(1); // Second column.
gridParams.setMargins(0, 0, 10, 0);
colorDotView = new TextView(context);
colorDotView.setLayoutParams(gridParams);
gridLayout.addView(colorDotView);
updateCategoryColorDot();
mEditText = new EditText(context);
mEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
mEditText.setText(category.colorString());
mEditText.addTextChangedListener(new TextWatcher() {
gridParams = new GridLayout.LayoutParams();
gridParams.rowSpec = GridLayout.spec(0); // First row.
gridParams.columnSpec = GridLayout.spec(2); // Third column.
colorEditText = new EditText(context);
colorEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
colorEditText.setTextLocale(Locale.US);
colorEditText.setText(category.getColorString());
colorEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@@ -81,29 +106,94 @@ public class SegmentCategoryListPreference extends ListPreference {
}
@Override
public void afterTextChanged(Editable s) {
public void afterTextChanged(Editable edit) {
try {
String colorString = s.toString();
String colorString = edit.toString();
final int colorStringLength = colorString.length();
if (!colorString.startsWith("#")) {
s.insert(0, "#"); // recursively calls back into this method
edit.insert(0, "#"); // Recursively calls back into this method.
return;
}
if (colorString.length() > 7) {
s.delete(7, colorString.length());
final int maxColorStringLength = 7; // #RRGGBB
if (colorStringLength > maxColorStringLength) {
edit.delete(maxColorStringLength, colorStringLength);
return;
}
final int color = Color.parseColor(colorString);
colorDotView.setText(SegmentCategory.getCategoryColorDot(color));
categoryColor = Color.parseColor(colorString);
updateCategoryColorDot();
} catch (IllegalArgumentException ex) {
// ignore
// Ignore.
}
}
});
mEditText.setLayoutParams(new TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 1f));
row.addView(mEditText);
colorEditText.setLayoutParams(gridParams);
gridLayout.addView(colorEditText);
table.addView(row);
builder.setView(table);
gridParams = new GridLayout.LayoutParams();
gridParams.rowSpec = GridLayout.spec(1); // Second row.
gridParams.columnSpec = GridLayout.spec(0, 1); // First and second column.
TextView opacityLabel = new TextView(context);
opacityLabel.setText(str("revanced_sb_color_opacity_label"));
opacityLabel.setLayoutParams(gridParams);
gridLayout.addView(opacityLabel);
gridParams = new GridLayout.LayoutParams();
gridParams.rowSpec = GridLayout.spec(1); // Second row.
gridParams.columnSpec = GridLayout.spec(2); // Third column.
opacityEditText = new EditText(context);
opacityEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
opacityEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable edit) {
try {
String editString = edit.toString();
final int opacityStringLength = editString.length();
final int maxOpacityStringLength = 4; // [0.00, 1.00]
if (opacityStringLength > maxOpacityStringLength) {
edit.delete(maxOpacityStringLength, opacityStringLength);
return;
}
final float opacity = opacityStringLength == 0
? 0
: Float.parseFloat(editString);
if (opacity < 0) {
categoryOpacity = 0;
edit.replace(0, opacityStringLength, "0");
return;
} else if (opacity > 1.0f) {
categoryOpacity = 1;
edit.replace(0, opacityStringLength, "1.0");
return;
} else if (!editString.endsWith(".")) {
// Ignore "0." and "1." until the user finishes entering a valid number.
categoryOpacity = opacity;
}
updateCategoryColorDot();
} catch (NumberFormatException ex) {
// Should never happen.
Logger.printException(() -> "Could not parse opacity string", ex);
}
}
});
opacityEditText.setLayoutParams(gridParams);
gridLayout.addView(opacityEditText);
updateOpacityText();
builder.setView(gridLayout);
builder.setTitle(category.title.toString());
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
@@ -111,8 +201,8 @@ public class SegmentCategoryListPreference extends ListPreference {
});
builder.setNeutralButton(str("revanced_sb_reset_color"), (dialog, which) -> {
try {
category.resetColor();
updateTitle();
category.resetColorAndOpacity();
updateTitleFromCategory();
Utils.showToastShort(str("revanced_sb_color_reset"));
} catch (Exception ex) {
Logger.printException(() -> "setNeutralButton failure", ex);
@@ -120,8 +210,9 @@ public class SegmentCategoryListPreference extends ListPreference {
});
builder.setNegativeButton(android.R.string.cancel, null);
mClickedDialogEntryIndex = findIndexOfValue(getValue());
builder.setSingleChoiceItems(getEntries(), mClickedDialogEntryIndex, (dialog, which) -> mClickedDialogEntryIndex = which);
selectedDialogEntryIndex = findIndexOfValue(getValue());
builder.setSingleChoiceItems(getEntries(), selectedDialogEntryIndex,
(dialog, which) -> selectedDialogEntryIndex = which);
} catch (Exception ex) {
Logger.printException(() -> "onPrepareDialogBuilder failure", ex);
}
@@ -130,30 +221,51 @@ public class SegmentCategoryListPreference extends ListPreference {
@Override
protected void onDialogClosed(boolean positiveResult) {
try {
if (positiveResult && mClickedDialogEntryIndex >= 0 && getEntryValues() != null) {
String value = getEntryValues()[mClickedDialogEntryIndex].toString();
if (positiveResult && selectedDialogEntryIndex >= 0 && getEntryValues() != null) {
String value = getEntryValues()[selectedDialogEntryIndex].toString();
if (callChangeListener(value)) {
setValue(value);
category.setBehaviour(Objects.requireNonNull(CategoryBehaviour.byReVancedKeyValue(value)));
SegmentCategory.updateEnabledCategories();
}
String colorString = mEditText.getText().toString();
try {
if (!colorString.equals(category.colorString())) {
String colorString = colorEditText.getText().toString();
if (!colorString.equals(category.getColorString()) || categoryOpacity != category.getOpacity()) {
category.setColor(colorString);
category.setOpacity(categoryOpacity);
Utils.showToastShort(str("revanced_sb_color_changed"));
}
} catch (IllegalArgumentException ex) {
Utils.showToastShort(str("revanced_sb_color_invalid"));
}
updateTitle();
updateTitleFromCategory();
}
} catch (Exception ex) {
Logger.printException(() -> "onDialogClosed failure", ex);
}
}
private void updateTitle() {
setTitle(category.getTitleWithColorDot());
private void applyOpacityToCategoryColor() {
categoryColor = applyOpacityToColor(categoryColor, categoryOpacity);
}
private void updateTitleFromCategory() {
categoryColor = category.getColorNoOpacity();
categoryOpacity = category.getOpacity();
applyOpacityToCategoryColor();
setTitle(category.getTitleWithColorDot(categoryColor));
}
private void updateCategoryColorDot() {
applyOpacityToCategoryColor();
colorDotView.setText(SegmentCategory.getCategoryColorDot(categoryColor));
}
private void updateOpacityText() {
opacityEditText.setText(String.format(Locale.US, "%.2f", categoryOpacity));
}
}

View File

@@ -23,12 +23,15 @@ public class SponsorSegment implements Comparable<SponsorSegment> {
@NonNull
public final StringRef title;
public final int apiVoteType;
public final boolean shouldHighlight;
/**
* If the option should be highlighted for VIP users.
*/
public final boolean highlightIfVipAndVideoIsLocked;
SegmentVote(@NonNull StringRef title, int apiVoteType, boolean shouldHighlight) {
SegmentVote(@NonNull StringRef title, int apiVoteType, boolean highlightIfVipAndVideoIsLocked) {
this.title = title;
this.apiVoteType = apiVoteType;
this.shouldHighlight = shouldHighlight;
this.highlightIfVipAndVideoIsLocked = highlightIfVipAndVideoIsLocked;
}
}

View File

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

View File

@@ -816,6 +816,14 @@ public final class app/revanced/patches/spotify/lite/ondemand/OnDemandPatchKt {
public static final fun getOnDemandPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/spotify/misc/UnlockPremiumPatchKt {
public static final fun getUnlockPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/spotify/misc/fix/SpoofSignaturePatchKt {
public static final fun getSpoofSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/spotify/navbar/PremiumNavbarTabPatchKt {
public static final fun getPremiumNavbarTabPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
@@ -1463,6 +1471,10 @@ public final class app/revanced/patches/youtube/video/quality/RememberVideoQuali
public static final fun getRememberVideoQualityPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/video/quality/VideoQualityPatchKt {
public static final fun getVideoQualityPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/video/speed/PlaybackSpeedPatchKt {
public static final fun getPlaybackSpeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

View File

@@ -5,10 +5,10 @@ import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
import app.revanced.patches.all.misc.transformation.transformInstructionsPatch
internal const val EXTENSION_CLASS_DESCRIPTOR_PREFIX =
private const val EXTENSION_CLASS_DESCRIPTOR_PREFIX =
"Lapp/revanced/extension/all/connectivity/wifi/spoof/SpoofWifiPatch"
internal const val EXTENSION_CLASS_DESCRIPTOR = "$EXTENSION_CLASS_DESCRIPTOR_PREFIX;"
private const val EXTENSION_CLASS_DESCRIPTOR = "$EXTENSION_CLASS_DESCRIPTOR_PREFIX;"
@Suppress("unused")
val spoofWifiPatch = bytecodePatch(

View File

@@ -8,9 +8,8 @@ import org.w3c.dom.Element
@Suppress("unused")
val changeVersionCodePatch = resourcePatch(
name = "Change version code",
description = "Changes the version code of the app. By default the highest version code is set. " +
"This allows older versions of an app to be installed " +
"if their version code is set to the same or a higher value and can stop app stores to update the app.",
description = "Changes the version code of the app. This will turn off app store updates " +
"and allows downgrading an existing app install to an older app version.",
use = false,
) {
val versionCode by intOption(
@@ -21,7 +20,8 @@ val changeVersionCodePatch = resourcePatch(
"Highest" to Int.MAX_VALUE,
),
title = "Version code",
description = "The version code to use",
description = "The version code to use. Using the highest value turns off app store " +
"updates and allows downgrading an existing app install to an older app version.",
required = true,
) { versionCode -> versionCode!! >= 1 }

View File

@@ -14,7 +14,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
val hideSponsoredStoriesPatch = bytecodePatch(
name = "Hide 'Sponsored Stories'",
) {
compatibleWith("com.facebook.katana")
compatibleWith("com.facebook.katana"("490.0.0.63.82"))
execute {
val sponsoredDataModelTemplateMethod = getSponsoredDataModelTemplateFingerprint.originalMethod

View File

@@ -17,7 +17,7 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
internal const val EXTENSION_CLASS_DESCRIPTOR =
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/music/spoof/SpoofClientPatch;"
// TODO: Replace this patch with spoofVideoStreamsPatch once possible.

View File

@@ -1,7 +1,10 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com") { clientIdOption ->
compatibleWith("com.rubenmayayo.reddit")
@@ -23,14 +26,15 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com")
// region Patch user agent.
// Use a random number as the platform in the user agent string.
val platformName = (0..100000).random()
val platformParameter = 0
buildUserAgentFingerprint.method.addInstructions(
0,
"const-string p$platformParameter, \"$platformName\"",
)
// Use a random user agent.
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
buildUserAgentFingerprint.let {
val userAgentTemplateIndex = it.stringMatches!!.first().index
val register = it.method.getInstruction<OneRegisterInstruction>(userAgentTemplateIndex).registerA
it.method.replaceInstruction(userAgentTemplateIndex, "const-string v$register, \"$userAgent\"")
}
// endregion
}

View File

@@ -8,7 +8,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
val spoofClientPatch = spoofClientPatch(redirectUri = "infinity://localhost") { clientIdOption ->
compatibleWith("ml.docilealligator.infinityforreddit", "ml.docilealligator.infinityforreddit.plus")
compatibleWith(
"ml.docilealligator.infinityforreddit",
"ml.docilealligator.infinityforreddit.plus",
"ml.docilealligator.infinityforreddit.patreon"
)
val clientId by clientIdOption

View File

@@ -11,7 +11,11 @@ val unlockSubscriptionPatch = bytecodePatch(
) {
dependsOn(spoofClientPatch)
compatibleWith("ml.docilealligator.infinityforreddit", "ml.docilealligator.infinityforreddit.plus")
compatibleWith(
"ml.docilealligator.infinityforreddit",
"ml.docilealligator.infinityforreddit.plus",
"ml.docilealligator.infinityforreddit.patreon"
)
execute {
setOf(

View File

@@ -17,7 +17,7 @@ import org.w3c.dom.Element
@Suppress("MemberVisibilityCanBePrivate")
abstract class BasePreference(
val key: String? = null,
val titleKey: String = "${key}_title",
val titleKey: String? = "${key}_title",
val summaryKey: String? = "${key}_summary",
val icon: String? = null,
val layout: String? = null,
@@ -35,7 +35,7 @@ abstract class BasePreference(
open fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element =
ownerDocument.createElement(tag).apply {
key?.let { setAttribute("android:key", it) }
setAttribute("android:title", "@string/${titleKey}")
titleKey?.let { setAttribute("android:title", "@string/${titleKey}") }
summaryKey?.let { addSummary(it) }
icon?.let {
setAttribute("android:icon", it)

View File

@@ -17,7 +17,7 @@ import org.w3c.dom.Document
@Suppress("MemberVisibilityCanBePrivate")
open class PreferenceCategory(
key: String? = null,
titleKey: String = "${key}_title",
titleKey: String? = "${key}_title",
icon: String? = null,
layout: String? = null,
sorting: Sorting = Sorting.BY_TITLE,

View File

@@ -35,7 +35,7 @@ fun spoofVideoStreamsPatch(
executeBlock: BytecodePatchContext.() -> Unit = {},
) = bytecodePatch(
name = "Spoof video streams",
description = "Spoofs the client video streams to fix playback.",
description = "Adds options to spoof the client video streams to fix playback.",
) {
block()

View File

@@ -0,0 +1,18 @@
package app.revanced.patches.spotify.misc
import app.revanced.patcher.fingerprint
internal val accountAttributeFingerprint = fingerprint {
custom { _, c -> c.endsWith("internal/AccountAttribute;") }
}
internal val productStateProtoFingerprint = fingerprint {
returns("Ljava/util/Map;")
custom { _, classDef ->
classDef.endsWith("ProductStateProto;")
}
}
internal val buildQueryParametersFingerprint = fingerprint {
strings("trackRows", "device_type:tablet")
}

View File

@@ -0,0 +1,5 @@
package app.revanced.patches.spotify.misc.fix
import app.revanced.patcher.fingerprint
internal val getAppSignatureFingerprint = fingerprint { strings("Failed to get the application signatures") }

View File

@@ -0,0 +1,33 @@
package app.revanced.patches.spotify.misc.fix
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
val spoofSignaturePatch = bytecodePatch(
name = "Spoof signature",
description = "Spoofs the signature of the app to fix various functions of the app.",
) {
compatibleWith("com.spotify.music")
execute {
getAppSignatureFingerprint.method.apply {
val failedToGetSignaturesStringMatch = getAppSignatureFingerprint.stringMatches!!.first()
val concatSignaturesIndex = indexOfFirstInstructionReversedOrThrow(
failedToGetSignaturesStringMatch.index,
Opcode.MOVE_RESULT_OBJECT,
)
val register = getInstruction<OneRegisterInstruction>(concatSignaturesIndex).registerA
val expectedSignature = "d6a6dced4a85f24204bf9505ccc1fce114cadb32"
replaceInstruction(concatSignaturesIndex, "const-string v$register, \"$expectedSignature\"")
}
}
}

View File

@@ -1,11 +0,0 @@
package app.revanced.patches.spotify.navbar
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
internal val addNavBarItemFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
literal { showBottomNavigationItemsTextId }
}

View File

@@ -1,50 +1,12 @@
package app.revanced.patches.spotify.navbar
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
internal var showBottomNavigationItemsTextId = -1L
private set
internal var premiumTabId = -1L
private set
private val premiumNavbarTabResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
execute {
premiumTabId = resourceMappings["id", "premium_tab"]
showBottomNavigationItemsTextId = resourceMappings[
"bool",
"show_bottom_navigation_items_text",
]
}
}
import app.revanced.patches.spotify.misc.unlockPremiumPatch
@Deprecated("Superseded by unlockPremiumPatch", ReplaceWith("unlockPremiumPatch"))
@Suppress("unused")
val premiumNavbarTabPatch = bytecodePatch(
name = "Premium navbar tab",
description = "Hides the premium tab from the navigation bar.",
) {
dependsOn(premiumNavbarTabResourcePatch)
compatibleWith("com.spotify.music")
// If the navigation bar item is the premium tab, do not add it.
execute {
addNavBarItemFingerprint.method.addInstructions(
0,
"""
const v1, $premiumTabId
if-ne p5, v1, :continue
return-void
:continue
nop
""",
)
}
dependsOn(unlockPremiumPatch)
}

View File

@@ -11,7 +11,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal const val EXTENSION_CLASS_DESCRIPTOR =
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tiktok/settings/AdPersonalizationActivityHook;"
val settingsPatch = bytecodePatch(

View File

@@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR =
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/tudortmund/lockscreen/ShowOnLockscreenPatch;"
@Suppress("unused")

View File

@@ -11,7 +11,7 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
internal const val EXTENSION_CLASS_DESCRIPTOR =
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/HideGetPremiumPatch;"
val hideGetPremiumPatch = bytecodePatch(

View File

@@ -50,7 +50,7 @@ private val downloadsResourcePatch = resourcePatch {
}
}
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/DownloadsPatch;"
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/DownloadsPatch;"
internal const val BUTTON_DESCRIPTOR = "Lapp/revanced/extension/youtube/videoplayer/ExternalDownloadButton;"

View File

@@ -15,8 +15,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
val enableSeekbarTappingPatch = bytecodePatch(
name = "Seekbar tapping",
description = "Adds an option to enable tap-to-seek on the seekbar of the video player.",
name = "Enable tap to seek",
description = "Adds an option to enable tap to seek on the seekbar of the video player.",
) {
dependsOn(
sharedExtensionPatch,

View File

@@ -23,7 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR =
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/NavigationButtonsPatch;"
val navigationButtonsPatch = bytecodePatch(

View File

@@ -43,7 +43,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
val hidePlayerOverlayButtonsPatch = bytecodePatch(
name = "Hide player overlay buttons",
description = "Adds options to hide the player cast, autoplay, caption button and next/ previous buttons.",
description = "Adds options to hide the player Cast, Autoplay, Captions, and Previous & Next buttons.",
) {
dependsOn(
sharedExtensionPatch,

View File

@@ -6,7 +6,9 @@ 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.shared.misc.settings.preference.ListPreference
import app.revanced.patches.youtube.layout.buttons.navigation.navigationButtonsPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.navigation.hookNavigationButtonCreated
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.getReference
@@ -15,7 +17,7 @@ import com.android.tools.smali.dexlib2.Opcode
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/youtube/patches/ChangeFormFactorPatch;"
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeFormFactorPatch;"
@Suppress("unused")
val changeFormFactorPatch = bytecodePatch(
@@ -26,6 +28,7 @@ val changeFormFactorPatch = bytecodePatch(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
navigationButtonsPatch
)
compatibleWith(
@@ -50,6 +53,8 @@ val changeFormFactorPatch = bytecodePatch(
)
)
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
createPlayerRequestBodyWithModelFingerprint.method.apply {
val formFactorEnumClass = formFactorEnumConstructorFingerprint.originalClassDef.type

View File

@@ -49,7 +49,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val hideEndscreenCardsPatch = bytecodePatch(
name = "Hide endscreen cards",
name = "Hide end screen cards",
description = "Adds an option to hide suggested video cards at the end of videos.",
) {
dependsOn(

View File

@@ -22,7 +22,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val hideEndScreenSuggestedVideoPatch = bytecodePatch(
name = "Hide end screen suggested video",
description = "Adds an option to hide the recommended video at the end of each video.",
description = "Adds an option to hide the suggested video at the end of videos.",
) {
dependsOn(
sharedExtensionPatch,

View File

@@ -14,7 +14,7 @@ import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR =
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/DisableFullscreenAmbientModePatch;"
val disableFullscreenAmbientModePatch = bytecodePatch(

View File

@@ -142,6 +142,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
PreferenceScreenPreference(
key = "revanced_hide_description_components_screen",
preferences = setOf(
SwitchPreference("revanced_hide_ai_generated_video_summary_section"),
SwitchPreference("revanced_hide_attributes_section"),
SwitchPreference("revanced_hide_chapters_section"),
SwitchPreference("revanced_hide_info_cards_section"),
@@ -154,13 +155,14 @@ val hideLayoutComponentsPatch = bytecodePatch(
PreferenceScreenPreference(
"revanced_comments_screen",
preferences = setOf(
SwitchPreference("revanced_hide_comments_chat_summary"),
SwitchPreference("revanced_hide_comments_ai_chat_summary"),
SwitchPreference("revanced_hide_comments_ai_summary"),
SwitchPreference("revanced_hide_comments_by_members_header"),
SwitchPreference("revanced_hide_comments_section"),
SwitchPreference("revanced_hide_comments_create_a_short_button"),
SwitchPreference("revanced_hide_comments_timestamp_and_emoji_buttons"),
SwitchPreference("revanced_hide_comments_preview_comment"),
SwitchPreference("revanced_hide_comments_thanks_button"),
SwitchPreference("revanced_hide_comments_timestamp_and_emoji_buttons"),
),
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
),

View File

@@ -159,7 +159,7 @@ private const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/pat
@Suppress("unused")
val hideShortsComponentsPatch = bytecodePatch(
name = "Hide Shorts components",
description = "Adds options to hide components related to YouTube Shorts.",
description = "Adds options to hide components related to Shorts.",
) {
dependsOn(
sharedExtensionPatch,

View File

@@ -134,7 +134,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/
@Suppress("unused")
val miniplayerPatch = bytecodePatch(
name = "Miniplayer",
description = "Adds options to change the in app minimized player."
description = "Adds options to change the in-app minimized player."
) {
dependsOn(
sharedExtensionPatch,

View File

@@ -98,20 +98,6 @@ internal val rollingNumberTextViewFingerprint = fingerprint {
}
}
internal val shortsTextViewFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("L", "L")
opcodes(
Opcode.INVOKE_SUPER, // first instruction of method
Opcode.IF_NEZ,
null,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
)
}
internal val textComponentConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.CONSTRUCTOR, AccessFlags.PRIVATE)
strings("TextComponent")

View File

@@ -1,9 +1,7 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike
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.instructions
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
@@ -169,51 +167,7 @@ val returnYouTubeDislikePatch = bytecodePatch(
// endregion
// region Hook for non-litho Short videos.
shortsTextViewFingerprint.method.apply {
val insertIndex = shortsTextViewFingerprint.patternMatch!!.endIndex + 1
// If the field is true, the TextView is for a dislike button.
val isDisLikesBooleanInstruction = instructions.first { instruction ->
instruction.opcode == Opcode.IGET_BOOLEAN
} as ReferenceInstruction
val isDisLikesBooleanReference = isDisLikesBooleanInstruction.reference
// Like/Dislike button TextView field.
val textViewFieldInstruction = instructions.first { instruction ->
instruction.opcode == Opcode.IGET_OBJECT
} as ReferenceInstruction
val textViewFieldReference = textViewFieldInstruction.reference
// Check if the hooked TextView object is that of the dislike button.
// If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted.
// Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward.
addInstructionsWithLabels(
insertIndex,
"""
# Check, if the TextView is for a dislike button
iget-boolean v0, p0, $isDisLikesBooleanReference
if-eqz v0, :is_like
# Hook the TextView, if it is for the dislike button
iget-object v0, p0, $textViewFieldReference
invoke-static {v0}, $EXTENSION_CLASS_DESCRIPTOR->setShortsDislikes(Landroid/view/View;)Z
move-result v0
if-eqz v0, :ryd_disabled
return-void
:is_like
:ryd_disabled
nop
""",
)
}
// endregion
// region Hook for litho Shorts
// region Hook Shorts
// Filter that parses the video id from the UI
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
@@ -255,22 +209,25 @@ val returnYouTubeDislikePatch = bytecodePatch(
)
}
// Rolling Number text views use the measured width of the raw string for layout.
// Modify the measure text calculation to include the left drawable separator if needed.
val patternMatch = rollingNumberMeasureAnimatedTextFingerprint.patternMatch!!
// Additional check to verify the opcodes are at the start of the method
if (patternMatch.startIndex != 0) throw PatchException("Unexpected opcode location")
val endIndex = patternMatch.endIndex
rollingNumberMeasureAnimatedTextFingerprint.method.apply {
val measuredTextWidthRegister = getInstruction<OneRegisterInstruction>(endIndex).registerA
rollingNumberMeasureAnimatedTextFingerprint.let {
// Rolling Number text views use the measured width of the raw string for layout.
// Modify the measure text calculation to include the left drawable separator if needed.
val patternMatch = it.patternMatch!!
// Verify the opcodes are at the start of the method.
if (patternMatch.startIndex != 0) throw PatchException("Unexpected opcode location")
val endIndex = patternMatch.endIndex
addInstructions(
endIndex + 1,
"""
invoke-static {p1, v$measuredTextWidthRegister}, $EXTENSION_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
move-result v$measuredTextWidthRegister
""",
)
it.method.apply {
val measuredTextWidthRegister = getInstruction<OneRegisterInstruction>(endIndex).registerA
addInstructions(
endIndex + 1,
"""
invoke-static {p1, v$measuredTextWidthRegister}, $EXTENSION_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
move-result v$measuredTextWidthRegister
"""
)
}
}
// Additional text measurement method. Used if YouTube decides not to animate the likes count
@@ -291,15 +248,14 @@ val returnYouTubeDislikePatch = bytecodePatch(
)
}
}
// The rolling number Span is missing styling since it's initially set as a String.
// Modify the UI text view and use the styled like/dislike Span.
// Initial TextView is set in this method.
val initiallyCreatedTextViewMethod = rollingNumberTextViewFingerprint.method
// Videos less than 24 hours after uploaded, like counts will be updated in real time.
// Whenever like counts are updated, TextView is set in this method.
arrayOf(
initiallyCreatedTextViewMethod,
// The rolling number Span is missing styling since it's initially set as a String.
// Modify the UI text view and use the styled like/dislike Span.
// Initial TextView is set in this method.
rollingNumberTextViewFingerprint.method,
// Videos less than 24 hours after uploaded, like counts will be updated in real time.
// Whenever like counts are updated, TextView is set in this method.
rollingNumberTextViewAnimationUpdateFingerprint.method,
).forEach { insertMethod ->
insertMethod.apply {
@@ -315,9 +271,9 @@ val returnYouTubeDislikePatch = bytecodePatch(
addInstructions(
setTextIndex,
"""
invoke-static {v$textViewRegister, v$textSpanRegister}, $EXTENSION_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textSpanRegister
""",
invoke-static {v$textViewRegister, v$textSpanRegister}, $EXTENSION_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
move-result-object v$textSpanRegister
"""
)
}
}

View File

@@ -18,7 +18,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/WideSearchbarPatch;"
val wideSearchbarPatch = bytecodePatch(
name = "Wide searchbar",
name = "Wide search bar",
description = "Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.",
) {
dependsOn(

View File

@@ -12,9 +12,11 @@ import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_43_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
@@ -44,8 +46,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
val spoofAppVersionPatch = bytecodePatch(
name = "Spoof app version",
description = "Adds an option to trick YouTube into thinking you are running an older version of the app. " +
"This can be used to restore old UI elements and features. " +
"Patching 19.16.39 includes additional older spoofing targets.",
"This can be used to restore old UI elements and features."
) {
dependsOn(
spoofAppVersionResourcePatch,
@@ -58,8 +59,8 @@ val spoofAppVersionPatch = bytecodePatch(
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
// "19.25.37", // Cannot be supported because the lowest spoof target is higher.
// "19.34.42", // Cannot be supported because the lowest spoof target is higher.
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
@@ -71,27 +72,35 @@ val spoofAppVersionPatch = bytecodePatch(
addResources("youtube", "layout.spoofappversion.spoofAppVersionPatch")
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
SwitchPreference("revanced_spoof_app_version"),
if (is_19_17_or_greater) {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
// Group the switch and list preference together, since General menu is sorted by name
// and the preferences can be scattered apart with non English langauges.
PreferenceCategory(
titleKey = null,
sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = setOf(
SwitchPreference("revanced_spoof_app_version"),
if (is_19_43_or_greater) {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
)
} else {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
entriesKey = "revanced_spoof_app_version_target_legacy_entries",
entryValuesKey = "revanced_spoof_app_version_target_legacy_entry_values"
)
}
)
} else {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
entriesKey = "revanced_spoof_app_version_target_legacy_entries",
entryValuesKey = "revanced_spoof_app_version_target_legacy_entry_values"
)
}
)
)
/**
* If a user really wants to spoof to very old versions with the latest app target
* they can modify the import/export spoof version. But when spoofing the 19.20.xx
* or earlier the Library tab can crash due to missing image resources trying to load.
* As a temporary workaround, do not set an image in the toolbar when the enum name is UNKNOWN.
* If spoofing to target 19.20 or earlier the Library tab can crash due to
* missing image resources. As a workaround, do not set an image in the
* toolbar when the enum name is UNKNOWN.
*/
toolBarButtonFingerprint.method.apply {
val getDrawableIndex = indexOfGetDrawableInstruction(this)

View File

@@ -8,7 +8,10 @@ import app.revanced.patcher.patch.stringOption
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.InputType
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
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.preference.TextPreference
import app.revanced.patches.youtube.layout.seekbar.seekbarColorPatch
@@ -71,6 +74,9 @@ val themePatch = bytecodePatch(
)
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
lithoColorHookPatch,
seekbarColorPatch,
versionCheckPatch,
@@ -78,23 +84,30 @@ val themePatch = bytecodePatch(
dependsOn(
settingsPatch,
resourceMappingPatch,
addResourcesPatch,
)
execute {
addResources("youtube", "layout.theme.themeResourcePatch")
PreferenceScreen.SEEKBAR.addPreferences(
val preferences = mutableSetOf<BasePreference>(
SwitchPreference("revanced_seekbar_custom_color"),
TextPreference("revanced_seekbar_custom_color_primary", inputType = InputType.TEXT_CAP_CHARACTERS),
)
if (is_19_25_or_greater) {
PreferenceScreen.SEEKBAR.addPreferences(
TextPreference("revanced_seekbar_custom_color_accent", inputType = InputType.TEXT_CAP_CHARACTERS),
preferences += TextPreference(
"revanced_seekbar_custom_color_accent",
inputType = InputType.TEXT_CAP_CHARACTERS
)
}
PreferenceScreen.SEEKBAR.addPreferences(
PreferenceCategory(
titleKey = null,
sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = preferences
)
)
// Edit theme colors via resources.
document("res/values/colors.xml").use { document ->
@@ -125,7 +138,6 @@ val themePatch = bytecodePatch(
colorValue: String,
) {
document(resourceFile).use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
resourcesNode.appendChild(
@@ -133,7 +145,7 @@ val themePatch = bytecodePatch(
setAttribute("name", colorName)
setAttribute("category", "color")
textContent = colorValue
},
}
)
}
}
@@ -152,11 +164,10 @@ val themePatch = bytecodePatch(
// Edit splash screen files and change the background color,
// if the background colors are set.
if (darkThemeBackgroundColor != null && lightThemeBackgroundColor != null) {
val splashScreenResourceFiles =
listOf(
"res/drawable/quantum_launchscreen_youtube.xml",
"res/drawable-sw600dp/quantum_launchscreen_youtube.xml",
)
val splashScreenResourceFiles = listOf(
"res/drawable/quantum_launchscreen_youtube.xml",
"res/drawable-sw600dp/quantum_launchscreen_youtube.xml",
)
splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile ->
document(resourceFile).use { document ->
@@ -174,36 +185,34 @@ val themePatch = bytecodePatch(
// Fix the splash screen dark mode background color.
// In 19.32+ the dark mode splash screen is white and fades to black.
// Maybe it's a bug in YT, or maybe it intentionally. Who knows.
document("res/values-night/styles.xml").use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
val childNodes = resourcesNode.childNodes
document("res/values-night-v27/styles.xml").use { document ->
// Create a night mode specific override for the splash screen background.
val style = document.createElement("style")
style.setAttribute("name", "Theme.YouTube.Home")
style.setAttribute("parent", "@style/Base.V27.Theme.YouTube.Home")
for (i in 0 until childNodes.length) {
val node = childNodes.item(i) as? Element ?: continue
val nodeAttributeName = node.getAttribute("name")
if (nodeAttributeName.startsWith("Theme.YouTube.Launcher")) {
val nodeAttributeParent = node.getAttribute("parent")
val style = document.createElement("style")
style.setAttribute("name", "Theme.YouTube.Home")
style.setAttribute("parent", nodeAttributeParent)
val windowItem = document.createElement("item")
windowItem.setAttribute("name", "android:windowBackground")
windowItem.textContent = "@color/$splashBackgroundColor"
style.appendChild(windowItem)
resourcesNode.removeChild(node)
resourcesNode.appendChild(style)
}
// Fix status and navigation bar showing white on some Android devices,
// such as SDK 28 Android 10 medium tablet.
val colorSplashBackgroundColor = "@color/$splashBackgroundColor"
arrayOf(
"android:navigationBarColor" to colorSplashBackgroundColor,
"android:windowBackground" to colorSplashBackgroundColor,
"android:colorBackground" to colorSplashBackgroundColor,
"colorPrimaryDark" to colorSplashBackgroundColor,
"android:windowLightStatusBar" to "false",
).forEach { (name, value) ->
val styleItem = document.createElement("item")
styleItem.setAttribute("name", name)
styleItem.textContent = value
style.appendChild(styleItem)
}
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
resourcesNode.appendChild(style)
}
}
}
},
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
}
)
compatibleWith(

View File

@@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
val openLinksExternallyPatch = bytecodePatch(
name = "Open links externally",
description = "Adds an option to always open links in your browser instead of in the in-app-browser.",
description = "Adds an option to always open links in your browser instead of the in-app browser.",
) {
dependsOn(
transformInstructionsPatch(

View File

@@ -27,7 +27,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
lateinit var addLithoFilter: (String) -> Unit
private set
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/components/LithoFilterPatch;"
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/components/LithoFilterPatch;"
val lithoFilterPatch = bytecodePatch(
description = "Hooks the method which parses the bytes into a ComponentContext to filter components.",

View File

@@ -16,6 +16,23 @@ internal val actionBarSearchResultsFingerprint = fingerprint {
literal { actionBarSearchResultsViewMicId }
}
internal val toolbarLayoutFingerprint = fingerprint {
accessFlags(AccessFlags.PROTECTED, AccessFlags.CONSTRUCTOR)
literal { toolbarContainerId }
}
/**
* Matches to https://android.googlesource.com/platform/frameworks/support/+/9eee6ba/v7/appcompat/src/android/support/v7/widget/Toolbar.java#963
*/
internal val appCompatToolbarBackButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/graphics/drawable/Drawable;")
parameters()
custom { methodDef, classDef ->
classDef.type == "Landroid/support/v7/widget/Toolbar;"
}
}
/**
* Matches to the class found in [pivotBarConstructorFingerprint].
*/

View File

@@ -8,6 +8,7 @@ import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
@@ -18,12 +19,16 @@ import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.util.MethodUtil
internal var imageOnlyTabResourceId = -1L
@@ -32,6 +37,8 @@ internal var actionBarSearchResultsViewMicId = -1L
private set
internal var ytFillBellId = -1L
private set
internal var toolbarContainerId = -1L
private set
private val navigationBarHookResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
@@ -40,6 +47,7 @@ private val navigationBarHookResourcePatch = resourcePatch {
imageOnlyTabResourceId = resourceMappings["layout", "image_only_tab"]
actionBarSearchResultsViewMicId = resourceMappings["layout", "action_bar_search_results_view_mic"]
ytFillBellId = resourceMappings["drawable", "yt_fill_bell_black_24"]
toolbarContainerId = resourceMappings["id", "toolbar_container"]
}
}
@@ -47,6 +55,8 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/shared/NavigationBar;"
internal const val EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR =
"Lapp/revanced/extension/youtube/shared/NavigationBar\$NavigationButton;"
private const val EXTENSION_TOOLBAR_INTERFACE =
"Lapp/revanced/extension/youtube/shared/NavigationBar${'$'}AppCompatToolbarPatchInterface;"
lateinit var hookNavigationButtonCreated: (String) -> Unit
@@ -143,11 +153,58 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
)
}
// Hook the back button visibility.
toolbarLayoutFingerprint.method.apply {
val index = indexOfFirstInstructionOrThrow {
opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type ==
"Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;"
}
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction(
index + 1,
"invoke-static { v$register }, ${EXTENSION_CLASS_DESCRIPTOR}->setToolbar(Landroid/widget/FrameLayout;)V"
)
}
// Add interface for extensions code to call obfuscated methods.
appCompatToolbarBackButtonFingerprint.let {
it.classDef.apply {
interfaces.add(EXTENSION_TOOLBAR_INTERFACE)
val definingClass = type
val obfuscatedMethodName = it.originalMethod.name
val returnType = "Landroid/graphics/drawable/Drawable;"
methods.add(
ImmutableMethod(
definingClass,
"patch_getNavigationIcon",
listOf(),
returnType,
AccessFlags.PUBLIC.value or AccessFlags.FINAL.value,
null,
null,
MutableMethodImplementation(2),
).toMutable().apply {
addInstructions(
0,
"""
invoke-virtual { p0 }, $definingClass->$obfuscatedMethodName()$returnType
move-result-object v0
return-object v0
"""
)
}
)
}
}
hookNavigationButtonCreated = { extensionClassDescriptor ->
navigationBarHookCallbackFingerprint.method.addInstruction(
0,
"invoke-static { p0, p1 }, " +
"$extensionClassDescriptor->navigationTabCreated" +
"invoke-static { p0, p1 }, $extensionClassDescriptor->navigationTabCreated" +
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
)
}

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.misc.playertype
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -15,6 +16,12 @@ internal val playerTypeFingerprint = fingerprint {
custom { _, classDef -> classDef.endsWith("/YouTubePlayerOverlaysLayout;") }
}
internal val reelWatchPagerFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/view/View;")
literal { reelWatchPlayerId }
}
internal val videoStateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")

View File

@@ -4,15 +4,34 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerTypeHookPatch;"
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/PlayerTypeHookPatch;"
internal var reelWatchPlayerId = -1L
private set
private val playerTypeHookResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
execute {
reelWatchPlayerId = resourceMappings["id", "reel_watch_player"]
}
}
val playerTypeHookPatch = bytecodePatch(
description = "Hook to get the current player type and video playback state.",
) {
dependsOn(sharedExtensionPatch)
dependsOn(sharedExtensionPatch, playerTypeHookResourcePatch)
execute {
playerTypeFingerprint.method.addInstruction(
@@ -20,6 +39,17 @@ val playerTypeHookPatch = bytecodePatch(
"invoke-static {p1}, $EXTENSION_CLASS_DESCRIPTOR->setPlayerType(Ljava/lang/Enum;)V",
)
reelWatchPagerFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(reelWatchPlayerId)
val registerIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT)
val viewRegister = getInstruction<OneRegisterInstruction>(registerIndex).registerA
addInstruction(
registerIndex + 1,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->onShortsCreate(Landroid/view/View;)V"
)
}
videoStateFingerprint.method.apply {
val endIndex = videoStateFingerprint.patternMatch!!.endIndex
val videoStateFieldName = getInstruction<ReferenceInstruction>(endIndex).reference
@@ -27,9 +57,9 @@ val playerTypeHookPatch = bytecodePatch(
addInstructions(
0,
"""
iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field
invoke-static {v0}, $EXTENSION_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V
""",
iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field
invoke-static {v0}, $EXTENSION_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V
"""
)
}
}

View File

@@ -20,7 +20,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
val removeTrackingQueryParameterPatch = bytecodePatch(
name = "Remove tracking query parameter",
description = "Adds an option to remove the tracking info from links you share.",
description = "Adds an option to remove the tracking parameter from links you share.",
) {
dependsOn(
sharedExtensionPatch,

View File

@@ -301,11 +301,9 @@ object PreferenceScreen : BasePreferenceScreen() {
summaryKey = null,
)
// Don't sort, because title sorting scatters the custom color preferences.
val SEEKBAR = Screen(
key = "revanced_settings_screen_07_seekbar",
summaryKey = null,
sorting = Sorting.UNSORTED,
)
val SWIPE_CONTROLS = Screen(
key = "revanced_settings_screen_08_swipe_controls",
@@ -323,6 +321,7 @@ object PreferenceScreen : BasePreferenceScreen() {
val VIDEO = Screen(
key = "revanced_settings_screen_12_video",
summaryKey = null,
sorting = Sorting.BY_KEY,
)
override fun commit(screen: PreferenceScreenPreference) {

View File

@@ -0,0 +1,118 @@
package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
internal var videoQualityBottomSheetListFragmentTitle = -1L
private set
internal var videoQualityQuickMenuAdvancedMenuDescription = -1L
private set
private val advancedVideoQualityMenuResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
execute {
// Used for the old type of the video quality menu.
videoQualityBottomSheetListFragmentTitle = resourceMappings[
"layout",
"video_quality_bottom_sheet_list_fragment_title",
]
videoQualityQuickMenuAdvancedMenuDescription = resourceMappings[
"string",
"video_quality_quick_menu_advanced_menu_description",
]
}
}
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/playback/quality/AdvancedVideoQualityMenuPatch;"
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/components/AdvancedVideoQualityMenuFilter;"
internal val advancedVideoQualityMenuPatch = bytecodePatch {
dependsOn(
advancedVideoQualityMenuResourcePatch,
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
lithoFilterPatch,
recyclerViewTreeHookPatch,
)
execute {
addResources("youtube", "video.quality.advancedVideoQualityMenuPatch")
settingsMenuVideoQualityGroup.add(
SwitchPreference("revanced_advanced_video_quality_menu")
)
// region Patch for the old type of the video quality menu.
// Used for regular videos when spoofing to old app version,
// and for the Shorts quality flyout on newer app versions.
videoQualityMenuViewInflateFingerprint.let {
it.method.apply {
val checkCastIndex = it.patternMatch!!.endIndex
val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$listViewRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
"showAdvancedVideoQualityMenu(Landroid/widget/ListView;)V",
)
}
}
// Force YT to add the 'advanced' quality menu for Shorts.
videoQualityMenuOptionsFingerprint.let {
val patternMatch = it.patternMatch!!
val startIndex = patternMatch.startIndex
val insertIndex = patternMatch.endIndex
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
it.method.apply {
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// A condition controls whether to show the three or four items quality menu.
// Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructions(
insertIndex,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$register
"""
)
}
}
// endregion
// region Patch for the new type of the video quality menu.
addRecyclerViewTreeHook(EXTENSION_CLASS_DESCRIPTOR)
// Required to check if the video quality menu is currently shown in order to click on the "Advanced" item.
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
// endregion
}
}

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -35,3 +36,41 @@ internal val videoQualitySetterFingerprint = fingerprint {
)
strings("menu_item_video_quality")
}
internal val videoQualityMenuOptionsFingerprint = fingerprint {
accessFlags(AccessFlags.STATIC)
returns("[L")
parameters("Landroid/content/Context", "L", "L")
opcodes(
Opcode.CONST_4, // First instruction of method.
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.IF_NEZ,
)
literal { videoQualityQuickMenuAdvancedMenuDescription }
}
internal val videoQualityMenuViewInflateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters("L", "L", "L")
opcodes(
Opcode.INVOKE_SUPER,
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
)
literal { videoQualityBottomSheetListFragmentTitle }
}

View File

@@ -10,7 +10,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.newVideoQualityChangedFingerprint
import app.revanced.patches.youtube.video.information.onCreateHook
@@ -22,47 +22,47 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/playback/quality/RememberVideoQualityPatch;"
val rememberVideoQualityPatch = bytecodePatch(
name = "Remember video quality",
description = "Adds an option to remember the last video quality selected.",
) {
val rememberVideoQualityPatch = bytecodePatch {
dependsOn(
sharedExtensionPatch,
videoInformationPatch,
playerTypeHookPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
),
)
execute {
addResources("youtube", "video.quality.rememberVideoQualityPatch")
PreferenceScreen.VIDEO.addPreferences(
SwitchPreference("revanced_remember_video_quality_last_selected"),
ListPreference(
key = "revanced_video_quality_default_wifi",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
),
settingsMenuVideoQualityGroup.addAll(listOf(
ListPreference(
key = "revanced_video_quality_default_mobile",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
),
)
ListPreference(
key = "revanced_video_quality_default_wifi",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
),
SwitchPreference("revanced_remember_video_quality_last_selected"),
ListPreference(
key = "revanced_shorts_quality_default_mobile",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
),
ListPreference(
key = "revanced_shorts_quality_default_wifi",
summaryKey = null,
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values",
),
SwitchPreference("revanced_remember_shorts_quality_last_selected")
))
/*
* The following code works by hooking the method which is called when the user selects a video quality

View File

@@ -0,0 +1,48 @@
package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
/**
* Video quality settings. Used to organize all speed related settings together.
*/
internal val settingsMenuVideoQualityGroup = mutableSetOf<BasePreference>()
@Suppress("unused")
val videoQualityPatch = bytecodePatch(
name = "Video quality",
description = "Adds options to use the advanced video quality menu and set default video qualities."
) {
dependsOn(
rememberVideoQualityPatch,
advancedVideoQualityMenuPatch,
)
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
)
)
execute {
PreferenceScreen.VIDEO.addPreferences(
// Keep the preferences organized together.
PreferenceCategory(
key = "revanced_01_video_key", // Dummy key to force the quality preferences first.
titleKey = null,
sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = settingsMenuVideoQualityGroup
)
)
}
}

View File

@@ -1,20 +1,29 @@
package app.revanced.patches.youtube.video.speed
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.video.speed.button.playbackSpeedButtonPatch
import app.revanced.patches.youtube.video.speed.custom.customPlaybackSpeedPatch
import app.revanced.patches.youtube.video.speed.remember.rememberPlaybackSpeedPatch
/**
* Speed menu settings. Used to organize all speed related settings together.
*/
internal val settingsMenuVideoSpeedGroup = mutableSetOf<BasePreference>()
@Suppress("unused")
val playbackSpeedPatch = bytecodePatch(
name = "Playback speed",
description = "Adds options to customize available playback speeds, remember the last playback speed selected " +
description = "Adds options to customize available playback speeds, set default a playback speed, " +
"and show a speed dialog button in the video player.",
) {
dependsOn(
playbackSpeedButtonPatch,
customPlaybackSpeedPatch,
rememberPlaybackSpeedPatch,
playbackSpeedButtonPatch,
)
compatibleWith(
@@ -26,6 +35,18 @@ val playbackSpeedPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
),
)
)
execute {
PreferenceScreen.VIDEO.addPreferences(
PreferenceCategory(
key = "revanced_zz_video_key", // Dummy key to force the speed settings last.
titleKey = null,
sorting = Sorting.UNSORTED,
tag = "app.revanced.extension.shared.settings.preference.NoTitlePreferenceCategory",
preferences = settingsMenuVideoSpeedGroup
)
)
}
}

View File

@@ -5,6 +5,7 @@ import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playercontrols.*
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
@@ -35,11 +36,12 @@ val playbackSpeedButtonPatch = bytecodePatch(
description = "Adds the option to display playback speed dialog button in the video player.",
) {
dependsOn(
playbackSpeedButtonResourcePatch,
customPlaybackSpeedPatch,
playerControlsPatch,
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
customPlaybackSpeedPatch,
playbackSpeedButtonResourcePatch,
playerControlsPatch,
)
execute {

View File

@@ -25,8 +25,8 @@ import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.video.speed.settingsMenuVideoSpeedGroup
import app.revanced.util.*
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
@@ -60,24 +60,29 @@ internal val customPlaybackSpeedPatch = bytecodePatch(
) {
dependsOn(
sharedExtensionPatch,
lithoFilterPatch,
settingsPatch,
recyclerViewTreeHookPatch,
customPlaybackSpeedResourcePatch,
addResourcesPatch,
versionCheckPatch
lithoFilterPatch,
versionCheckPatch,
recyclerViewTreeHookPatch,
customPlaybackSpeedResourcePatch
)
execute {
addResources("youtube", "video.speed.custom.customPlaybackSpeedPatch")
PreferenceScreen.VIDEO.addPreferences(
SwitchPreference("revanced_custom_speed_menu"),
TextPreference("revanced_custom_playback_speeds", inputType = InputType.TEXT_MULTI_LINE),
settingsMenuVideoSpeedGroup.addAll(
listOf(
SwitchPreference("revanced_custom_speed_menu"),
TextPreference(
"revanced_custom_playback_speeds",
inputType = InputType.TEXT_MULTI_LINE
),
)
)
if (is_19_25_or_greater) {
PreferenceScreen.VIDEO.addPreferences(
settingsMenuVideoSpeedGroup.add(
TextPreference("revanced_speed_tap_and_hold", inputType = InputType.NUMBER_DECIMAL),
)
}

View File

@@ -9,10 +9,10 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.video.information.*
import app.revanced.patches.youtube.video.speed.custom.customPlaybackSpeedPatch
import app.revanced.patches.youtube.video.speed.settingsMenuVideoSpeedGroup
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
private const val EXTENSION_CLASS_DESCRIPTOR =
@@ -22,26 +22,29 @@ internal val rememberPlaybackSpeedPatch = bytecodePatch {
dependsOn(
sharedExtensionPatch,
settingsPatch,
videoInformationPatch,
customPlaybackSpeedPatch,
addResourcesPatch,
videoInformationPatch,
customPlaybackSpeedPatch
)
execute {
addResources("youtube", "video.speed.remember.rememberPlaybackSpeedPatch")
PreferenceScreen.VIDEO.addPreferences(
SwitchPreference("revanced_remember_playback_speed_last_selected"),
ListPreference(
key = "revanced_playback_speed_default",
summaryKey = null,
// Entries and values are set by the extension code based on the actual speeds available.
entriesKey = null,
entryValuesKey = null,
),
settingsMenuVideoSpeedGroup.addAll(
listOf(
ListPreference(
key = "revanced_playback_speed_default",
summaryKey = null,
// Entries and values are set by the extension code based on the actual speeds available.
entriesKey = null,
entryValuesKey = null,
),
SwitchPreference("revanced_remember_playback_speed_last_selected")
)
)
onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted")
userSelectedPlaybackSpeedHook(
EXTENSION_CLASS_DESCRIPTOR,
"userSelectedPlaybackSpeed",

View File

@@ -1,43 +0,0 @@
package app.revanced.patches.youtube.video.videoqualitymenu
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val videoQualityMenuOptionsFingerprint = fingerprint {
accessFlags(AccessFlags.STATIC)
returns("[L")
parameters("Landroid/content/Context", "L", "L")
opcodes(
Opcode.CONST_4, // First instruction of method.
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.IF_NEZ,
)
literal { videoQualityQuickMenuAdvancedMenuDescription }
}
internal val videoQualityMenuViewInflateFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters("L", "L", "L")
opcodes(
Opcode.INVOKE_SUPER,
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
)
literal { videoQualityBottomSheetListFragmentTitle }
}

View File

@@ -1,135 +1,10 @@
package app.revanced.patches.youtube.video.videoqualitymenu
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.addRecyclerViewTreeHook
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.recyclerViewTreeHookPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
internal var videoQualityBottomSheetListFragmentTitle = -1L
private set
internal var videoQualityQuickMenuAdvancedMenuDescription = -1L
private set
private val restoreOldVideoQualityMenuResourcePatch = resourcePatch {
dependsOn(
settingsPatch,
resourceMappingPatch,
addResourcesPatch,
)
execute {
addResources("youtube", "video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch")
PreferenceScreen.VIDEO.addPreferences(
SwitchPreference("revanced_restore_old_video_quality_menu"),
)
// Used for the old type of the video quality menu.
videoQualityBottomSheetListFragmentTitle = resourceMappings[
"layout",
"video_quality_bottom_sheet_list_fragment_title",
]
videoQualityQuickMenuAdvancedMenuDescription = resourceMappings[
"string",
"video_quality_quick_menu_advanced_menu_description",
]
}
}
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/components/VideoQualityMenuFilterPatch;"
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;"
import app.revanced.patches.youtube.video.quality.videoQualityPatch
@Suppress("unused")
val restoreOldVideoQualityMenuPatch = bytecodePatch(
name = "Restore old video quality menu",
description = "Adds an option to restore the old video quality menu with specific video resolution options.",
) {
dependsOn(
sharedExtensionPatch,
restoreOldVideoQualityMenuResourcePatch,
lithoFilterPatch,
recyclerViewTreeHookPatch,
)
compatibleWith(
"com.google.android.youtube"(
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
),
)
execute {
// region Patch for the old type of the video quality menu.
// Used for regular videos when spoofing to old app version,
// and for the Shorts quality flyout on newer app versions.
videoQualityMenuViewInflateFingerprint.method.apply {
val checkCastIndex = videoQualityMenuViewInflateFingerprint.patternMatch!!.endIndex
val listViewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$listViewRegister }, " +
"$EXTENSION_CLASS_DESCRIPTOR->" +
"showOldVideoQualityMenu(Landroid/widget/ListView;)V",
)
}
// Force YT to add the 'advanced' quality menu for Shorts.
val patternMatch = videoQualityMenuOptionsFingerprint.patternMatch!!
val startIndex = patternMatch.startIndex
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
val insertIndex = patternMatch.endIndex
videoQualityMenuOptionsFingerprint.method.apply {
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// A condition controls whether to show the three or four items quality menu.
// Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructions(
insertIndex,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$register
""",
)
}
// endregion
// region Patch for the new type of the video quality menu.
addRecyclerViewTreeHook(EXTENSION_CLASS_DESCRIPTOR)
// Required to check if the video quality menu is currently shown in order to click on the "Advanced" item.
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
// endregion
}
}
@Deprecated("Use 'Video Quality' instead.")
val restoreOldVideoQualityMenuPatch = bytecodePatch {
dependsOn(videoQualityPatch)
}

View File

@@ -178,8 +178,7 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Long): Int {
*
* @return if the method contains a literal with the given value.
*/
fun Method.containsLiteralInstruction(literal: Long) =
indexOfFirstLiteralInstruction(literal) >= 0
fun Method.containsLiteralInstruction(literal: Long) = indexOfFirstLiteralInstruction(literal) >= 0
/**
* Traverse the class hierarchy starting from the given root class.
@@ -205,25 +204,22 @@ fun BytecodePatchContext.traverseClassHierarchy(targetClass: MutableClass, callb
* if the [Instruction] is not a [ReferenceInstruction] or the [Reference] is not of type [T].
* @see ReferenceInstruction
*/
inline fun <reified T : Reference> Instruction.getReference() =
(this as? ReferenceInstruction)?.reference as? T
inline fun <reified T : Reference> Instruction.getReference() = (this as? ReferenceInstruction)?.reference as? T
/**
* @return The index of the first opcode specified, or -1 if not found.
* @see indexOfFirstInstructionOrThrow
*/
fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int =
indexOfFirstInstruction(0, targetOpcode)
fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int = indexOfFirstInstruction(0, targetOpcode)
/**
* @param startIndex Optional starting index to start searching from.
* @return The index of the first opcode specified, or -1 if not found.
* @see indexOfFirstInstructionOrThrow
*/
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int =
indexOfFirstInstruction(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstruction(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
@@ -251,23 +247,21 @@ fun Method.indexOfFirstInstruction(startIndex: Int = 0, filter: Instruction.() -
* @throws PatchException
* @see indexOfFirstInstruction
*/
fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int =
indexOfFirstInstructionOrThrow(0, targetOpcode)
fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int = indexOfFirstInstructionOrThrow(0, targetOpcode)
/**
* @return The index of the first opcode specified, starting from the index specified.
* @throws PatchException
* @see indexOfFirstInstruction
*/
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int =
indexOfFirstInstructionOrThrow(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstructionOrThrow(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
*
* @return the index of the instruction
* @return The index of the instruction.
* @throws PatchException
* @see indexOfFirstInstruction
*/
@@ -288,10 +282,9 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, filter: Instructi
* @return -1 if the instruction is not found.
* @see indexOfFirstInstructionReversedOrThrow
*/
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int =
indexOfFirstInstructionReversed(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversed(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of matching instruction,
@@ -316,23 +309,21 @@ fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, filter: Inst
*
* @return -1 if the instruction is not found.
*/
fun Method.indexOfFirstInstructionReversed(targetOpcode: Opcode): Int =
indexOfFirstInstructionReversed {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionReversed(targetOpcode: Opcode): Int = indexOfFirstInstructionReversed {
opcode == targetOpcode
}
/**
* Get the index of matching instruction,
* starting from and [startIndex] and searching down.
*
* @param startIndex Optional starting index to search down from. Searching includes the start index.
* @return -1 if the instruction is not found.
* @return The index of the instruction.
* @see indexOfFirstInstructionReversed
*/
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int =
indexOfFirstInstructionReversedOrThrow(startIndex) {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversedOrThrow(startIndex) {
opcode == targetOpcode
}
/**
* Get the index of matching instruction,
@@ -340,16 +331,16 @@ fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targe
*
* @return -1 if the instruction is not found.
*/
fun Method.indexOfFirstInstructionReversedOrThrow(targetOpcode: Opcode): Int =
indexOfFirstInstructionReversedOrThrow {
opcode == targetOpcode
}
fun Method.indexOfFirstInstructionReversedOrThrow(targetOpcode: Opcode): Int = indexOfFirstInstructionReversedOrThrow {
opcode == targetOpcode
}
/**
* Get the index of matching instruction,
* starting from and [startIndex] and searching down.
*
* @param startIndex Optional starting index to search down from. Searching includes the start index.
* @return -1 if the instruction is not found.
* @return The index of the instruction.
* @see indexOfFirstInstructionReversed
*/
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, filter: Instruction.() -> Boolean): Int {
@@ -389,8 +380,7 @@ fun Method.findInstructionIndicesReversedOrThrow(filter: Instruction.() -> Boole
* _Returns an empty list if no indices are found_
* @see findInstructionIndicesReversedOrThrow
*/
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> =
findInstructionIndicesReversed { this.opcode == opcode }
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> = findInstructionIndicesReversed { this.opcode == opcode }
/**
* @return An immutable list of indices of the opcode in reverse order.
@@ -408,15 +398,18 @@ internal fun MutableMethod.insertFeatureFlagBooleanOverride(literal: Long, exten
val index = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(index).registerA
val operation = if (register < 16) "invoke-static { v$register }"
else "invoke-static/range { v$register .. v$register }"
val operation = if (register < 16) {
"invoke-static { v$register }"
} else {
"invoke-static/range { v$register .. v$register }"
}
addInstructions(
index + 1,
"""
$operation, $extensionsMethod
move-result v$register
"""
""",
)
}

View File

@@ -50,9 +50,9 @@ Second \"item\" text"</string>
This button usually appears when searching for a YT creator. -->
<!-- https://logos.fandom.com/wiki/YouTube/Yoodles -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- 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="ad.general.hideAdsResourcePatch">
@@ -156,6 +156,7 @@ Second \"item\" text"</string>
<patch id="layout.sponsorblock.sponsorBlockResourcePatch">
<!-- Translations should use language similar to 'revanced_ryd_compact_layout_title' -->
<!-- Toast shown if network connection times out. Translations of this should not be longer than the original English or the text can be clipped and not entirely shown. -->
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.formfactor.changeFormFactorPatch">
@@ -163,7 +164,6 @@ Second \"item\" text"</string>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.changeStartPagePatch">
</patch>
@@ -177,8 +177,6 @@ Second \"item\" text"</string>
</patch>
<patch id="layout.theme.themePatch">
</patch>
<patch id="layout.theme.themeResourcePatch">
</patch>
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
</patch>
<patch id="layout.thumbnails.alternativeThumbnailsPatch">
@@ -219,7 +217,7 @@ Second \"item\" text"</string>
</patch>
<patch id="video.hdr.disableHdrPatch">
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<patch id="video.quality.advancedVideoQualityMenuPatch">
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch>

View File

@@ -50,9 +50,9 @@ Second \"item\" text"</string>
This button usually appears when searching for a YT creator. -->
<!-- https://logos.fandom.com/wiki/YouTube/Yoodles -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- 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="ad.general.hideAdsResourcePatch">
@@ -156,6 +156,7 @@ Second \"item\" text"</string>
<patch id="layout.sponsorblock.sponsorBlockResourcePatch">
<!-- Translations should use language similar to 'revanced_ryd_compact_layout_title' -->
<!-- Toast shown if network connection times out. Translations of this should not be longer than the original English or the text can be clipped and not entirely shown. -->
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.formfactor.changeFormFactorPatch">
@@ -163,7 +164,6 @@ Second \"item\" text"</string>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.changeStartPagePatch">
</patch>
@@ -177,8 +177,6 @@ Second \"item\" text"</string>
</patch>
<patch id="layout.theme.themePatch">
</patch>
<patch id="layout.theme.themeResourcePatch">
</patch>
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
</patch>
<patch id="layout.thumbnails.alternativeThumbnailsPatch">
@@ -219,7 +217,7 @@ Second \"item\" text"</string>
</patch>
<patch id="video.hdr.disableHdrPatch">
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<patch id="video.quality.advancedVideoQualityMenuPatch">
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch>

View File

@@ -48,57 +48,6 @@ Second \"item\" text"</string>
Ų„ØĒØąØŦŲ…ØŠ Ų„ØēاØĒ ØŦØ¯ŲŠØ¯ØŠØŒ ØĒ؁ØļŲ„ Ø¨Ø˛ŲŠØ§ØąØŠ translate.revanced.app"</string>
<string name="revanced_language_DEFAULT">Ų„ØēØŠ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚</string>
<string name="revanced_language_AR">Ø§Ų„ØšØąØ¨ŲŠØŠ</string>
<string name="revanced_language_AZ">Azerbaijani</string>
<string name="revanced_language_BG">Bulgarian</string>
<string name="revanced_language_BN">Bengali</string>
<string name="revanced_language_CA">Catalan</string>
<string name="revanced_language_CS">Czech</string>
<string name="revanced_language_DA">Danish</string>
<string name="revanced_language_DE">German</string>
<string name="revanced_language_EL">Greek</string>
<string name="revanced_language_EN">English</string>
<string name="revanced_language_ES">Spanish</string>
<string name="revanced_language_ET">Estonian</string>
<string name="revanced_language_FA">ŲØ§ØąØŗŲ‰</string>
<string name="revanced_language_FI">Finnish</string>
<string name="revanced_language_FR">French - Français</string>
<string name="revanced_language_GU">Gujarati</string>
<string name="revanced_language_HI">Hindi</string>
<string name="revanced_language_HR">Croatian</string>
<string name="revanced_language_HU">Hungarian</string>
<string name="revanced_language_ID">Indonesian</string>
<string name="revanced_language_IT">Italian</string>
<string name="revanced_language_JA">Japanese</string>
<string name="revanced_language_KK">Kazakh</string>
<string name="revanced_language_KO">Korean</string>
<string name="revanced_language_LT">Lithuanian</string>
<string name="revanced_language_LV">Latvian</string>
<string name="revanced_language_MK">Macedonian</string>
<string name="revanced_language_MN">Mongolian</string>
<string name="revanced_language_MR">Marathi</string>
<string name="revanced_language_MS">Malay</string>
<string name="revanced_language_MY">Burmese</string>
<string name="revanced_language_NL">Dutch</string>
<string name="revanced_language_OR">Odia</string>
<string name="revanced_language_PA">Punjabi</string>
<string name="revanced_language_PL">Polish</string>
<string name="revanced_language_PT">Portugese</string>
<string name="revanced_language_RO">Romanian</string>
<string name="revanced_language_RU">Russian - Đ ŅƒŅŅĐēиК</string>
<string name="revanced_language_SK">Slovak</string>
<string name="revanced_language_SL">Slovene</string>
<string name="revanced_language_SR">Serbian</string>
<string name="revanced_language_SV">Swedish</string>
<string name="revanced_language_SW">Swahili</string>
<string name="revanced_language_TA">Tamil</string>
<string name="revanced_language_TE">Telugu</string>
<string name="revanced_language_TH">Thai</string>
<string name="revanced_language_TR">Turkish</string>
<string name="revanced_language_UK">Ukrainian</string>
<string name="revanced_language_UR">Urdu</string>
<string name="revanced_language_VI">Vietnamese</string>
<string name="revanced_language_ZH">Chinese</string>
<string name="revanced_pref_import_export_title">Ø§ØŗØĒŲŠØąØ§Ø¯ / ØĒØĩØ¯ŲŠØą</string>
<string name="revanced_pref_import_export_summary">Ø§ØŗØĒŲŠØąØ§Ø¯ / ØĒØĩØ¯ŲŠØą ØĨؚداداØĒ ReVanced</string>
<!-- Settings about dialog. -->
@@ -277,6 +226,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_artist_cards_title">ØĨØŽŲØ§ØĄ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ŲŲ†Ø§Ų†</string>
<string name="revanced_hide_artist_cards_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ŲŲ†Ø§Ų†</string>
<string name="revanced_hide_artist_cards_summary_off">؊ØĒŲ… ØšØąØļ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ŲŲ†Ø§Ų†</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">ØĨØŽŲØ§ØĄ \"Ų…Ų„ØŽØĩ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ø°ŲŠ ØĒŲ… ØĨŲ†Ø´Ø§Ø¤Ų‡ Ø¨ŲˆØ§ØŗØˇØŠ Ø§Ų„Ø°ŲƒØ§ØĄ Ø§Ų„Ø§ØĩØˇŲ†Ø§ØšŲŠ\"</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… Ų…Ų„ØŽØĩ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">؊ØĒŲ… ØšØąØļ Ų‚ØŗŲ… Ų…Ų„ØŽØĩ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_hide_attributes_section_title">ØĨØŽŲØ§ØĄ Ø§Ų„ØĩŲØ§ØĒ</string>
<string name="revanced_hide_attributes_section_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ ØŖŲ‚ØŗØ§Ų… Ø§Ų„ØŖŲ…Ø§ŲƒŲ† Ø§Ų„Ų…Ų…ŲŠØ˛ØŠØŒ Ø§Ų„ØŖŲ„ØšØ§Ø¨ØŒ Ø§Ų„Ų…ŲˆØŗŲŠŲ‚Ų‰ ŲˆØ§Ų„ØŖØ´ØŽØ§Øĩ Ø§Ų„Ų…Ø°ŲƒŲˆØąŲˆŲ†</string>
<string name="revanced_hide_attributes_section_summary_off">؊ØĒŲ… ØšØąØļ ØŖŲ‚ØŗØ§Ų… Ø§Ų„ØŖŲ…Ø§ŲƒŲ† Ø§Ų„Ų…Ų…ŲŠØ˛ØŠØŒ Ø§Ų„ØŖŲ„ØšØ§Ø¨ØŒ Ø§Ų„Ų…ŲˆØŗŲŠŲ‚Ų‰ ŲˆØ§Ų„ØŖØ´ØŽØ§Øĩ Ø§Ų„Ų…Ø°ŲƒŲˆØąŲˆŲ†</string>
@@ -313,9 +265,12 @@ Second \"item\" text"</string>
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">ŲŠØšØąØļ ؁؊ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ ذاØĒ Ø§Ų„ØĩŲ„ØŠ</string>
<string name="revanced_comments_screen_title">Ø§Ų„ØĒØšŲ„ŲŠŲ‚Ø§ØĒ</string>
<string name="revanced_comments_screen_summary">ØĨØŽŲØ§ØĄ ØŖŲˆ ØšØąØļ Ų…ŲƒŲˆŲ†Ø§ØĒ Ų‚ØŗŲ… Ø§Ų„ØĒØšŲ„ŲŠŲ‚Ø§ØĒ</string>
<string name="revanced_hide_comments_chat_summary_title">ØĨØŽŲØ§ØĄ \'Ų…Ų„ØŽØĩ Ø§Ų„Ų…Ø­Ø§Ø¯ØĢØŠ\'</string>
<string name="revanced_hide_comments_chat_summary_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų…Ų„ØŽØĩ Ø§Ų„Ų…Ø­Ø§Ø¯ØĢاØĒ</string>
<string name="revanced_hide_comments_chat_summary_summary_off">؊ØĒŲ… ØšØąØļ Ų…Ų„ØŽØĩ Ø§Ų„Ų…Ø­Ø§Ø¯ØĢاØĒ</string>
<string name="revanced_hide_comments_ai_chat_summary_title">ØĨØŽŲØ§ØĄ Ų…Ų„ØŽØĩ Ø¯ØąØ¯Ø´ØŠ Ø§Ų„Ø°ŲƒØ§ØĄ Ø§Ų„Ø§ØĩØˇŲ†Ø§ØšŲŠ</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų…Ų„ØŽØĩ Ø§Ų„Ų…Ø­Ø§Ø¯ØĢاØĒ</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">؊ØĒŲ… ØšØąØļ Ų…Ų„ØŽØĩ Ø§Ų„Ų…Ø­Ø§Ø¯ØĢاØĒ</string>
<string name="revanced_hide_comments_ai_summary_title">ØĨØŽŲØ§ØĄ Ų…Ų„ØŽØĩ ØĒØšŲ„ŲŠŲ‚Ø§ØĒ Ø§Ų„Ø°ŲƒØ§ØĄ Ø§Ų„Ø§ØĩØˇŲ†Ø§ØšŲŠ</string>
<string name="revanced_hide_comments_ai_summary_summary_on">Ų…Ų„ØŽØĩ Ø§Ų„ØĒØšŲ„ŲŠŲ‚Ø§ØĒ Ų…ØŽŲŲŠ</string>
<string name="revanced_hide_comments_ai_summary_summary_off">Ų…Ų„ØŽØĩ Ø§Ų„ØĒØšŲ„ŲŠŲ‚Ø§ØĒ Ų…ØšØąŲˆØļ</string>
<string name="revanced_hide_comments_by_members_header_title">ØĨØŽŲØ§ØĄ ØąØŖØŗ \'ØĒØšŲ„ŲŠŲ‚Ø§ØĒ Ø§Ų„ØŖØšØļØ§ØĄ\'</string>
<string name="revanced_hide_comments_by_members_header_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ ØšŲ„Ø§Ų…ØŠ ØĒØšŲ„ŲŠŲ‚Ø§ØĒ Ų…Ų† Ø§Ų„ØŖØšØļØ§ØĄ</string>
<string name="revanced_hide_comments_by_members_header_summary_off">؊ØĒŲ… ØšØąØļ ØšŲ„Ø§Ų…ØŠ ØĒØšŲ„ŲŠŲ‚Ø§ØĒ Ų…Ų† Ø§Ų„ØŖØšØļØ§ØĄ</string>
@@ -362,7 +317,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_on">؊ØĒŲ… ØĒØĩŲŲŠØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ ؁؊ ØšŲ„Ø§Ų…ØŠ Ø§Ų„ØĒØ¨ŲˆŲŠØ¨ Ø§Ų„Ø§Ø´ØĒØąØ§ŲƒØ§ØĒ Ø­ØŗØ¨ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_off">Ų„Ø§ ؊ØĒŲ… ØĒØĩŲŲŠØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ ؁؊ ØšŲ„Ø§Ų…ØŠ Ø§Ų„ØĒØ¨ŲˆŲŠØ¨ Ø§Ų„Ø§Ø´ØĒØąØ§ŲƒØ§ØĒ Ø­ØŗØ¨ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ</string>
<string name="revanced_hide_keyword_content_phrases_title">Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ Ø§Ų„Ų…ØąØ§Ø¯ ØĨØŽŲØ§Ø¤Ų‡Ø§</string>
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<string name="revanced_hide_keyword_content_phrases_summary">"Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ ŲˆØ§Ų„ØšØ¨Ø§ØąØ§ØĒ Ø§Ų„ØĒ؊ ØĒØąŲŠØ¯ ØĨØŽŲØ§ØĄŲ‡Ø§ØŒ ؅؁ØĩŲˆŲ„ØŠ Ø¨ØŗØˇŲˆØą ØŦØ¯ŲŠØ¯ØŠ
@@ -377,7 +332,7 @@ Second \"item\" text"</string>
â€ĸ Ų‚Ø¯ Ų„Ø§ ؊ØĒŲ… ØĨØŽŲØ§ØĄ بؚØļ Ų…ŲƒŲˆŲ†Ø§ØĒ ŲˆØ§ØŦŲ‡ØŠ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų…
â€ĸ Ø§Ų„Ø¨Ø­ØĢ ØšŲ† ŲƒŲ„Ų…ØŠ Ų…Ø§ Ų‚Ø¯ Ų„Ø§ ŲŠØšØˇŲŠ Ų†ØĒاØĻØŦ"</string>
<string name="revanced_hide_keyword_content_about_whole_words_title">Ų…ØˇØ§Ø¨Ų‚ØŠ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø¨ØŖŲƒŲ…Ų„Ų‡Ø§</string>
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<string name="revanced_hide_keyword_content_about_whole_words_summary">ØŗŲŠØ¤Ø¯ŲŠ ؈ØļØš ØšŲ„Ø§Ų…ØŠ Ø§Ų‚ØĒØ¨Ø§Øŗ Ų…Ø˛Ø¯ŲˆØŦØŠ Ø­ŲˆŲ„ ŲƒŲ„Ų…ØŠ ØąØĻŲŠØŗŲŠØŠ/ØšØ¨Ø§ØąØŠ ØĨŲ„Ų‰ Ų…Ų†Øš Ø§Ų„ØĒØˇØ§Ø¨Ų‚Ø§ØĒ Ø§Ų„ØŦØ˛ØĻŲŠØŠ Ų„ØšŲ†Ø§ŲˆŲŠŲ† Ø§Ų„ŲŲŠØ¯ŲŠŲˆ ŲˆØŖØŗŲ…Ø§ØĄ Ø§Ų„Ų‚Ų†ŲˆØ§ØĒ.&lt;br&gt;&lt;br&gt;ØšŲ„Ų‰ ØŗØ¨ŲŠŲ„ Ø§Ų„Ų…ØĢØ§Ų„ØŒ&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt; ØŗŲŠØŽŲŲŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ: &lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt;ŲˆŲ„ŲƒŲ† Ų„Ų† ŲŠØŽŲŲŠ: &lt;b&gt;What does fair use mean?&lt;/b&gt;</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="revanced_hide_keyword_toast_invalid_common">Ų„Ø§ ŲŠŲ…ŲƒŲ† Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ: %s</string>
@@ -404,7 +359,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_self_sponsor_ads_title">ØĨØŽŲØ§ØĄ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ØąØšØ§ŲŠØŠ Ø§Ų„Ø°Ø§ØĒŲŠØŠ</string>
<string name="revanced_hide_self_sponsor_ads_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ØąØšØ§ŲŠØŠ Ø§Ų„Ø°Ø§ØĒŲŠØŠ</string>
<string name="revanced_hide_self_sponsor_ads_summary_off">؊ØĒŲ… ØšØąØļ Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„ØąØšØ§ŲŠØŠ Ø§Ų„Ø°Ø§ØĒŲŠØŠ</string>
<string name="revanced_hide_products_banner_title">ØĨØŽŲØ§ØĄ Ų„Ø§ŲØĒØŠ Ų„ØšØąØļ Ø§Ų„Ų…Ų†ØĒØŦاØĒ</string>
<string name="revanced_hide_products_banner_title">ØĨØŽŲØ§ØĄ Ų„Ø§ŲØĒØŠ \"ØšØąØļ Ø§Ų„Ų…Ų†ØĒØŦاØĒ\"</string>
<string name="revanced_hide_products_banner_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø§Ų„Ø¨Ø§Ų†Øą</string>
<string name="revanced_hide_products_banner_summary_off">؊ØĒŲ… ØšØąØļ Ø§Ų„Ø¨Ø§Ų†Øą</string>
<string name="revanced_hide_end_screen_store_banner_title">ØĨØŽŲØ§ØĄ Ų„Ø§ŲØĒØŠ شاش؊ Ø§Ų„Ų…ØĒØŦØą Ø§Ų„Ų†Ų‡Ø§ØĻŲŠØŠ</string>
@@ -475,9 +430,9 @@ Second \"item\" text"</string>
<string name="revanced_disable_precise_seeking_gesture_summary_off">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØĨŲŠŲ…Ø§ØĄØŠ</string>
</patch>
<patch id="interaction.seekbar.enableSeekbarTappingPatch">
<string name="revanced_seekbar_tapping_title">ØĒŲ…ŲƒŲŠŲ† Ø§Ų„Ų†Ų‚Øą ØšŲ„Ų‰ Ø´ØąŲŠØˇ Ø§Ų„ŲˆŲ‚ØĒ</string>
<string name="revanced_seekbar_tapping_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„Ų†Ų‚Øą ØšŲ„Ų‰ Ø´ØąŲŠØˇ Ø§Ų„ŲˆŲ‚ØĒ (Ø´ØąŲŠØˇ ØĒŲ‚Ø¯Ų… Ø§Ų„ŲŲŠØ¯ŲŠŲˆ)</string>
<string name="revanced_seekbar_tapping_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„Ų†Ų‚Øą ØšŲ„Ų‰ Ø´ØąŲŠØˇ Ø§Ų„ŲˆŲ‚ØĒ (Ø´ØąŲŠØˇ ØĒŲ‚Ø¯Ų… Ø§Ų„ŲŲŠØ¯ŲŠŲˆ)</string>
<string name="revanced_seekbar_tapping_title">ØĒŲ…ŲƒŲŠŲ† Ø§Ų„Ų†Ų‚Øą Ų„Ų„Ø¨Ø­ØĢ</string>
<string name="revanced_seekbar_tapping_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„Ų†Ų‚Øą Ų„Ų„ØĒŲ†Ų‚Ų„</string>
<string name="revanced_seekbar_tapping_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„Ų†Ų‚Øą Ų„Ų„Ø¨Ø­ØĢ</string>
</patch>
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
<string name="revanced_swipe_brightness_title">Ø§Ų„ØĒØ­ŲƒŲ… Ø¨Ø§Ų„ØŗØˇŲˆØš ØšŲ† ØˇØąŲŠŲ‚ Ø§ŲŠŲ…Ø§ØĄØŠ Ø§Ų„ØĒŲ…ØąŲŠØą</string>
@@ -490,9 +445,9 @@ Second \"item\" text"</string>
اØļØ¨Øˇ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ ØšŲ† ØˇØąŲŠŲ‚ Ø§Ų„ØĒŲ…ØąŲŠØą ØšŲ…ŲˆØ¯ŲŠŲ‹Ø§ ØšŲ„Ų‰ Ø§Ų„ØŦØ§Ų†Ø¨ Ø§Ų„ØŖŲŠŲ…Ų† Ų…Ų† Ø§Ų„Ø´Ø§Ø´ØŠ"</string>
<string name="revanced_swipe_volume_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„ØĒŲ…ØąŲŠØą Ø§Ų„ØŗØąŲŠØš Ų„ØļØ¨Øˇ Ų…ØŗØĒŲˆŲ‰ Ø§Ų„Øĩ؈ØĒ ؁؊ ؈ØļØš Ų…Ų„ØĄ Ø§Ų„Ø´Ø§Ø´ØŠ</string>
<string name="revanced_swipe_press_to_engage_title">ØĒŲ…ŲƒŲŠŲ† ØĨŲŠŲ…Ø§ØĄØŠ Ø§Ų„ØļØēØˇ Ų„Ų„ØĒŲ…ØąŲŠØą</string>
<string name="revanced_swipe_press_to_engage_summary_on">؊ØĒŲ… ØĒŲ†Ø´ŲŠØˇ ØšŲ†Ø§ØĩØą Ø§Ų„ØĒØ­ŲƒŲ… ØšŲ† ØˇØąŲŠŲ‚ ØĨŲŠŲ…Ø§ØĄØŠ Ø§Ų„ØĒŲ…ØąŲŠØą ŲŲ‚Øˇ بØļØēØˇØŠ ØˇŲˆŲŠŲ„ØŠ</string>
<string name="revanced_swipe_press_to_engage_summary_off">ØĒŲ†Ø´ŲŠØˇ ØšŲ†Ø§ØĩØą Ø§Ų„ØĒØ­ŲƒŲ… ØšŲ† ØˇØąŲŠŲ‚ ØĨŲŠŲ…Ø§ØĄØŠ Ø§Ų„ØĒŲ…ØąŲŠØą ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ Ų…Ø¨Ø§Ø´ØąØŠ</string>
<string name="revanced_swipe_press_to_engage_title">ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØļØēØˇ ØšŲ„Ų‰ ØĨŲŠŲ…Ø§ØĄØŠ Ø§Ų„ØĒŲ…ØąŲŠØą Ø§Ų„ØŗØąŲŠØš</string>
<string name="revanced_swipe_press_to_engage_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØļØēØˇ Ų„Ų„ØĒŲ…ØąŲŠØą Ø§Ų„ØŗØąŲŠØš</string>
<string name="revanced_swipe_press_to_engage_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„ØļØēØˇ Ų„Ų„ØĒŲ…ØąŲŠØą Ø§Ų„ØŗØąŲŠØš</string>
<string name="revanced_swipe_haptic_feedback_title">Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string>
<string name="revanced_swipe_haptic_feedback_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string>
<string name="revanced_swipe_haptic_feedback_summary_off">ØĒŲ… ØĒØšØˇŲŠŲ„ Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛ ØšŲ†Ø¯ Ø§Ų„ØļØēØˇ</string>
@@ -663,7 +618,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_player_flyout_video_quality_footer_summary_off">؊ØĒŲ… ØšØąØļ ØĒØ°ŲŠŲŠŲ„ Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
</patch>
<patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch">
<string name="revanced_hide_player_previous_next_buttons_title">ØĨØŽŲØ§ØĄ ØŖØ˛ØąØ§Øą Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ØŗØ§Ø¨Ų‚ &amp; Ø§Ų„ØĒØ§Ų„ŲŠ</string>
<string name="revanced_hide_player_previous_next_buttons_title">ØĨØŽŲØ§ØĄ Ø˛ØąŲŠ \"Ø§Ų„ØŗØ§Ø¨Ų‚\" ؈ \"Ø§Ų„ØĒØ§Ų„ŲŠ\"</string>
<string name="revanced_hide_player_previous_next_buttons_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø§Ų„ØŖØ˛ØąØ§Øą</string>
<string name="revanced_hide_player_previous_next_buttons_summary_off">؊ØĒŲ… ØšØąØļ Ø§Ų„ØŖØ˛ØąØ§Øą</string>
<string name="revanced_hide_cast_button_title">ØĨØŽŲØ§ØĄ Ø˛Øą Ø§Ų„Ø¨ØĢ</string>
@@ -856,7 +811,6 @@ Second \"item\" text"</string>
<string name="revanced_ryd_enable_summary_on">؊ØĒŲ… ØšØąØļ Ų„Ų… ŲŠØšØŦØ¨Ų†ŲŠ</string>
<string name="revanced_ryd_enable_summary_off">Ų„Ø§ ؊ØĒŲ… ØšØąØļ Ų„Ų… ŲŠØšØŦØ¨Ų†ŲŠ</string>
<string name="revanced_ryd_shorts_title">ØšØąØļ Ų„Ų… ŲŠØšØŦŲ†ŲŠ ؁؊ ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts</string>
<string name="revanced_ryd_shorts_summary_on">؊ØĒŲ… ØšØąØļ ØšØ¯Ų… Ø§Ų„ØĨØšØŦاب ØšŲ„Ų‰ ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts</string>
<string name="revanced_ryd_shorts_summary_on_disclaimer">"؊ØĒŲ… ØšØąØļ Ų…ØąØ§ØĒ ØšØ¯Ų… Ø§Ų„ØĨØšØŦاب ؁؊ ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts
Ø§Ų„ØĒŲ‚ŲŠŲŠØ¯: Ų‚Ø¯ Ų„Ø§ ØĒØ¸Ų‡Øą Ų…ØąØ§ØĒ ØšØ¯Ų… Ø§Ų„ØĨØšØŦاب ؁؊ ؈ØļØš Ø§Ų„ØĒØĩŲØ­ Ø§Ų„Ų…ØĒØŽŲŲŠ"</string>
@@ -1054,6 +1008,8 @@ Second \"item\" text"</string>
<string name="revanced_sb_vote_downvote">اؚØĒØąØ§Øļ</string>
<string name="revanced_sb_vote_category">ØĒØēŲŠŲŠØą Ø§Ų„ŲØĻØŠ</string>
<string name="revanced_sb_vote_no_segments">Ų„Ø§ ØĒ؈ØŦد Ų…Ų‚Ø§ØˇØš Ų„Ų„ØĒØĩ؈؊ØĒ ØšŲ„ŲŠŲ‡Ø§</string>
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<string name="revanced_sb_vote_segment_time_to_from">%1$s ØĨŲ„Ų‰ %2$s</string>
<string name="revanced_sb_new_segment_choose_category">ا؎ØĒŲŠØ§Øą ؁ØĻØŠ Ø§Ų„Ų…Ų‚ØˇØš</string>
<string name="revanced_sb_new_segment_disabled_category">Ø§Ų„ŲØĻØŠ Ų…ØšØˇŲ„ØŠ ؁؊ Ø§Ų„ØĨؚداداØĒ. ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ŲØĻØŠ Ų„Ų„ØĨØąØŗØ§Ų„.</string>
<string name="revanced_sb_new_segment_title">Ų…Ų‚ØˇØš SponsorBlock ØŦØ¯ŲŠØ¯</string>
@@ -1101,6 +1057,7 @@ Second \"item\" text"</string>
<string name="revanced_sb_stats_saved_hour_format">%1$s ØŗØ§ØšØŠ %2$s Ø¯Ų‚ŲŠŲ‚ØŠ</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s Ø¯Ų‚ŲŠŲ‚ØŠ %2$s ØĢØ§Ų†ŲŠØŠ</string>
<string name="revanced_sb_stats_saved_second_format">%s ØĢØ§Ų†ŲŠØŠ</string>
<string name="revanced_sb_color_opacity_label">Ø§Ų„Ø´ŲØ§ŲŲŠØŠ:</string>
<string name="revanced_sb_color_dot_label">Ø§Ų„Ų„ŲˆŲ†:</string>
<string name="revanced_sb_color_changed">ØĒŲ… ØĒØēŲŠŲŠØą Ø§Ų„Ų„ŲˆŲ†</string>
<string name="revanced_sb_color_reset">ØĨؚاد؊ ØļØ¨Øˇ Ø§Ų„Ų„ŲˆŲ†</string>
@@ -1116,16 +1073,14 @@ Second \"item\" text"</string>
<string name="revanced_change_form_factor_entry_2">Ø§Ų„ØŦŲˆŲ‘Ø§Ų„</string>
<string name="revanced_change_form_factor_entry_3">Ø§Ų„ØŦŲ‡Ø§Ø˛ Ø§Ų„Ų„ŲˆØ­ŲŠ</string>
<string name="revanced_change_form_factor_entry_4">Automotive</string>
<string name="revanced_change_form_factor_user_dialog_message">"ØĒØĒØļŲ…Ų† Ø§Ų„ØĒØēŲŠŲŠØąØ§ØĒ:
<string name="revanced_change_form_factor_user_dialog_message">"Ø§Ų„ØĒØēŲŠŲŠØąØ§ØĒ ØĒØ´Ų…Ų„:
ØĒØŽØˇŲŠØˇ Ø§Ų„ØŦŲ‡Ø§Ø˛ Ø§Ų„Ų„ŲˆØ­ŲŠ
â€ĸ ØĨØŽŲØ§ØĄ Ų…Ų†Ø´ŲˆØąØ§ØĒ Ø§Ų„Ų…ØŦØĒŲ…Øš
ØĒØĩŲ…ŲŠŲ… Ø§Ų„ØŦŲ‡Ø§Ø˛ Ø§Ų„Ų„ŲˆØ­ŲŠ
â€ĸ Ų…Ø´Ø§ØąŲƒØ§ØĒ Ø§Ų„Ų…ØŦØĒŲ…Øš Ų…ØŽŲŲŠØŠ
ØĒØŽØˇŲŠØˇ Automotive
â€ĸ ØĨØŽŲØ§ØĄ Ų‚Ø§ØĻŲ…ØŠ ØŗØŦŲ„ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ
â€ĸ Ø§ØŗØĒؚاد؊ ØšŲ„Ø§Ų…ØŠ Ø§Ų„ØĒØ¨ŲˆŲŠØ¨ \"Ø§ØŗØĒŲƒØ´Ø§Ų\"
â€ĸ ؁ØĒØ­ ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts ؁؊ Ø§Ų„Ų…Ø´ØēŲ„ Ø§Ų„ØšØ§Ø¯ŲŠ
â€ĸ ØĒŲ†Ø¸ŲŠŲ… Ø§Ų„ØŽŲ„Ø§ØĩØŠ Ø­ØŗØ¨ Ø§Ų„Ų…ŲˆØļŲˆØšØ§ØĒ ŲˆØ§Ų„Ų‚Ų†Ø§ØŠ"</string>
ØĒØĩŲ…ŲŠŲ… Ø§Ų„ØŗŲŠØ§ØąØŠ
â€ĸ ؊ØĒŲ… ؁ØĒØ­ Shorts ؁؊ Ø§Ų„Ų…Ø´ØēŲ„ Ø§Ų„ØšØ§Ø¯ŲŠ
â€ĸ ؊ØĒŲ… ØĒŲ†Ø¸ŲŠŲ… Ø§Ų„ØŽŲ„Ø§ØĩØŠ Ø­ØŗØ¨ Ø§Ų„Ų…ŲˆØ§ØļŲŠØš ŲˆØ§Ų„Ų‚Ų†ŲˆØ§ØĒ"</string>
</patch>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<string name="revanced_spoof_app_version_title">ØŽŲØ¯Ø§Øš ØĨØĩØ¯Ø§Øą Ø§Ų„ØĒØˇØ¨ŲŠŲ‚</string>
@@ -1140,12 +1095,7 @@ Second \"item\" text"</string>
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<string name="revanced_spoof_app_version_target_title">Ø§Ų„Ų‡Ø¯Ų Ų…Ų† ØĒØēŲŠŲŠØą ØĨØĩØ¯Ø§Øą Ø§Ų„ØĒØˇØ¨ŲŠŲ‚</string>
<string name="revanced_spoof_app_version_target_entry_1">19.35.36 - Ø§ØŗØĒؚاد؊ ØŖŲŠŲ‚ŲˆŲ†Ø§ØĒ Ų…Ø´ØēŲ„ Shorts Ø§Ų„Ų‚Ø¯ŲŠŲ…ØŠ</string>
<string name="revanced_spoof_app_version_target_entry_2">19.26.42 - Ø§ØŗØĒؚاد؊ ØŖŲŠŲ‚ŲˆŲ†Ø§ØĒ Ø§Ų„ØĒŲ†Ų‚Ų„ Ø§Ų„Ų‚Ø¯ŲŠŲ…ØŠ</string>
<!-- 'RYD' is 'Return YouTube Dislike' -->
<string name="revanced_spoof_app_version_target_legacy_entry_1">18.33.40 - Ø§ØŗØĒؚاد؊ RYD ØšŲ„Ų‰ Shorts Ø¨ŲˆØļØš Ø§Ų„ØĒØŽŲŲŠ</string>
<string name="revanced_spoof_app_version_target_legacy_entry_2">18.20.39 - Ø§ØŗØĒؚاد؊ Ų‚Ø§ØĻŲ…ØŠ ØŗØąØšØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ØšØąŲŠØļØŠ &amp; Ø§Ų„ØŦŲˆØ¯ØŠ</string>
<string name="revanced_spoof_app_version_target_legacy_entry_3">18.09.39 - Ø§ØŗØĒؚاد؊ ØšŲ„Ø§Ų…ØŠ ØĒØ¨ŲˆŲŠØ¨ Ø§Ų„Ų…ŲƒØĒب؊</string>
<string name="revanced_spoof_app_version_target_legacy_entry_4">17.33.42 - Ø§ØŗØĒؚاد؊ ØąŲ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„ØĒØ´ØēŲŠŲ„ Ø§Ų„Ų‚Ø¯ŲŠŲ…</string>
<string name="revanced_spoof_app_version_target_entry_2">19.01.34 - Ø§ØŗØĒؚاد؊ ØŖŲŠŲ‚ŲˆŲ†Ø§ØĒ Ø§Ų„ØĒŲ†Ų‚Ų„ Ø§Ų„Ų‚Ø¯ŲŠŲ…ØŠ</string>
</patch>
<patch id="layout.startpage.changeStartPagePatch">
<string name="revanced_change_start_page_title">ØĒØšŲŠŲŠŲ† ØĩŲØ­ØŠ Ø§Ų„Ø¨Ø¯Ø§ŲŠØŠ</string>
@@ -1248,8 +1198,6 @@ Second \"item\" text"</string>
<string name="revanced_gradient_loading_screen_title">ØĒŲ…ŲƒŲŠŲ† شاش؊ Ø§Ų„ØĒØ­Ų…ŲŠŲ„ Ø§Ų„Ų…ØĒØ¯ØąØŦØŠ</string>
<string name="revanced_gradient_loading_screen_summary_on">ØŗØĒØ­ØĒ؈؊ شاش؊ Ø§Ų„ØĒØ­Ų…ŲŠŲ„ ØšŲ„Ų‰ ØŽŲ„ŲŲŠØŠ Ų…ØĒØ¯ØąØŦØŠ</string>
<string name="revanced_gradient_loading_screen_summary_off">ØŗØĒØ­ØĒ؈؊ شاش؊ Ø§Ų„ØĒØ­Ų…ŲŠŲ„ ØšŲ„Ų‰ ØŽŲ„ŲŲŠØŠ ØĢابØĒØŠ</string>
</patch>
<patch id="layout.theme.themeResourcePatch">
<string name="revanced_seekbar_custom_color_title">ØĒŲ…ŲƒŲŠŲ† Ų„ŲˆŲ† Ø´ØąŲŠØˇ ØĒŲ‚Ø¯Ų… Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ØŽØĩØĩ</string>
<string name="revanced_seekbar_custom_color_summary_on">؊ØĒŲ… ØšØąØļ Ų„ŲˆŲ† Ø´ØąŲŠØˇ ØĒŲ‚Ø¯Ų… Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ØŽØĩØĩ</string>
<string name="revanced_seekbar_custom_color_summary_off">؊ØĒŲ… ØšØąØļ Ų„ŲˆŲ† Ø´ØąŲŠØˇ ØĒŲ‚Ø¯Ų… Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ø§ØĩŲ„ŲŠ</string>
@@ -1341,8 +1289,8 @@ Second \"item\" text"</string>
</patch>
<patch id="misc.links.openLinksExternallyPatch">
<string name="revanced_external_browser_title">؁ØĒØ­ Ø§Ų„ØąŲˆØ§Ø¨Øˇ ؁؊ Ø§Ų„Ų…ØĒØĩŲØ­</string>
<string name="revanced_external_browser_summary_on">؁ØĒØ­ Ø§Ų„ØąŲˆØ§Ø¨Øˇ ØŽØ§ØąØŦŲŠŲ‹Ø§</string>
<string name="revanced_external_browser_summary_off">؁ØĒØ­ Ø§Ų„ØąŲˆØ§Ø¨Øˇ ؁؊ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚</string>
<string name="revanced_external_browser_summary_on">؁ØĒØ­ Ø§Ų„ØąŲˆØ§Ø¨Øˇ ؁؊ Ų…ØĒØĩŲØ­ ØŽØ§ØąØŦ؊</string>
<string name="revanced_external_browser_summary_off">؁ØĒØ­ Ø§Ų„ØąŲˆØ§Ø¨Øˇ ؁؊ Ų…ØĒØĩŲØ­ Ø¯Ø§ØŽŲ„ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚</string>
</patch>
<patch id="misc.privacy.removeTrackingQueryParameterPatch">
<string name="revanced_remove_tracking_query_parameter_title">ØĨØ˛Ø§Ų„ØŠ Ų…ØšŲ„Ų…ØŠ ØĒØĒبؚ Ø§Ų„Ø§ØŗØĒØšŲ„Ø§Ų…</string>
@@ -1355,6 +1303,7 @@ Second \"item\" text"</string>
<string name="revanced_disable_zoom_haptics_summary_off">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„Ø§Ų‡ØĒØ˛Ø§Ø˛</string>
</patch>
<patch id="video.audio.forceOriginalAudioPatch">
<string name="revanced_force_original_audio_title">ŲØąØļ Ų„ØēØŠ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØŖØĩŲ„ŲŠØŠ</string>
<string name="revanced_force_original_audio_summary_on">Ø§ØŗØĒØŽØ¯Ø§Ų… Ų„ØēØŠ Ø§Ų„Øĩ؈ØĒ Ø§Ų„ØŖØĩŲ„ŲŠØŠ</string>
<string name="revanced_force_original_audio_summary_off">Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„Øĩ؈ØĒ Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
<!-- 'Spoof video streams' should be the same translation used for revanced_spoof_video_streams_screen_title -->
@@ -1368,9 +1317,15 @@ Second \"item\" text"</string>
<string name="revanced_remember_video_quality_last_selected_summary_off">ØĒŲ†ØˇØ¨Ų‚ ØĒØēŲŠŲŠØąØ§ØĒ Ø§Ų„ØŦŲˆØ¯ØŠ ØšŲ„Ų‰ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ø­Ø§Ų„ŲŠ ŲŲ‚Øˇ</string>
<string name="revanced_video_quality_default_wifi_title">ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ ØšŲ„Ų‰ Ø´Ø¨ŲƒØŠ Wi-Fi</string>
<string name="revanced_video_quality_default_mobile_title">ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ ØšŲ„Ų‰ Ø´Ø¨ŲƒØŠ Ø§Ų„ØŦŲˆŲ‘ŲŽØ§Ų„</string>
<string name="revanced_remember_shorts_quality_last_selected_title">ØĒØ°ŲƒØą ØĒØēŲŠŲŠØąØ§ØĒ ØŦŲˆØ¯ØŠ Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">ØĒŲ†ØˇØ¨Ų‚ ØĒØēŲŠŲŠØąØ§ØĒ Ø§Ų„ØŦŲˆØ¯ØŠ ØšŲ„Ų‰ ØŦŲ…ŲŠØš ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">ØĒŲ†ØˇØ¨Ų‚ ØĒØēŲŠŲŠØąØ§ØĒ Ø§Ų„ØŦŲˆØ¯ØŠ ŲŲ‚Øˇ ØšŲ„Ų‰ ŲŲŠØ¯ŲŠŲˆ Short Ø§Ų„Ø­Ø§Ų„ŲŠ</string>
<string name="revanced_shorts_quality_default_wifi_title">ØŦŲˆØ¯ØŠ Shorts Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ ØšŲ„Ų‰ Ø´Ø¨ŲƒØŠ Wi-Fi</string>
<string name="revanced_shorts_quality_default_mobile_title">ØŦŲˆØ¯ØŠ Shorts Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ ØšŲ„Ų‰ Ø´Ø¨ŲƒØŠ Ø§Ų„ØŦŲˆØ§Ų„</string>
<string name="revanced_remember_video_quality_mobile">Ø§Ų„ØŦŲˆŲ‘Ø§Ų„</string>
<string name="revanced_remember_video_quality_wifi">Wi-Fi</string>
<string name="revanced_remember_video_quality_toast">ØĒŲ… ØĒØēŲŠŲŠØą ØŦŲˆØ¯ØŠ %1$s Ø§Ų„Ø§ŲØĒØąØ§ØļŲŠØŠ ØĨŲ„Ų‰: %2$s</string>
<string name="revanced_remember_video_quality_toast_shorts">ØĒŲ… ØĒØēŲŠŲŠØą ØŦŲˆØ¯ØŠ Shorts %1$s ØĨŲ„Ų‰: %2$s</string>
</patch>
<patch id="video.speed.button.playbackSpeedButtonPatch">
<string name="revanced_playback_speed_dialog_button_title">ØšØąØļ Ø˛Øą Ų…ØąØ¨Øš Ø­ŲˆØ§Øą Ø§Ų„ØŗØąØšØŠ</string>
@@ -1401,10 +1356,10 @@ Second \"item\" text"</string>
<string name="revanced_disable_hdr_video_summary_on">ØĒŲ… ØĒØšØˇŲŠŲ„ ŲŲŠØ¯ŲŠŲˆ HDR</string>
<string name="revanced_disable_hdr_video_summary_off">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† ŲŲŠØ¯ŲŠŲˆ HDR</string>
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<string name="revanced_restore_old_video_quality_menu_title">Ø§ØŗØĒؚاد؊ Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų‚Ø¯ŲŠŲ…ØŠ</string>
<string name="revanced_restore_old_video_quality_menu_summary_on">؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų‚Ø¯ŲŠŲ…ØŠ</string>
<string name="revanced_restore_old_video_quality_menu_summary_off">Ų„Ø§ ؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų‚Ø¯ŲŠŲ…ØŠ</string>
<patch id="video.quality.advancedVideoQualityMenuPatch">
<string name="revanced_advanced_video_quality_menu_title">ØĨØ¸Ų‡Ø§Øą Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ØĒŲ‚Ø¯Ų…ØŠ</string>
<string name="revanced_advanced_video_quality_menu_summary_on">؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ØĒŲ‚Ø¯Ų…ØŠ</string>
<string name="revanced_advanced_video_quality_menu_summary_off">Ų„Ø§ ؊ØĒŲ… ØšØąØļ Ų‚Ø§ØĻŲ…ØŠ ØŦŲˆØ¯ØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ØĒŲ‚Ø¯Ų…ØŠ</string>
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
<string name="revanced_slide_to_seek_title">ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØĒŲ…ØąŲŠØą Ų„Ų„ØĒŲ‚Ø¯ŲŠŲ… ØŖŲˆ Ø§Ų„ØĒØąØŦŲŠØš</string>

View File

@@ -50,9 +50,9 @@ Second \"item\" text"</string>
This button usually appears when searching for a YT creator. -->
<!-- https://logos.fandom.com/wiki/YouTube/Yoodles -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- 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="ad.general.hideAdsResourcePatch">
@@ -156,6 +156,7 @@ Second \"item\" text"</string>
<patch id="layout.sponsorblock.sponsorBlockResourcePatch">
<!-- Translations should use language similar to 'revanced_ryd_compact_layout_title' -->
<!-- Toast shown if network connection times out. Translations of this should not be longer than the original English or the text can be clipped and not entirely shown. -->
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.formfactor.changeFormFactorPatch">
@@ -163,7 +164,6 @@ Second \"item\" text"</string>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.changeStartPagePatch">
</patch>
@@ -177,8 +177,6 @@ Second \"item\" text"</string>
</patch>
<patch id="layout.theme.themePatch">
</patch>
<patch id="layout.theme.themeResourcePatch">
</patch>
<patch id="layout.thumbnails.bypassImageRegionRestrictionsPatch">
</patch>
<patch id="layout.thumbnails.alternativeThumbnailsPatch">
@@ -221,7 +219,7 @@ Second \"item\" text"</string>
</patch>
<patch id="video.hdr.disableHdrPatch">
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<patch id="video.quality.advancedVideoQualityMenuPatch">
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
</patch>

View File

@@ -48,57 +48,6 @@ Second \"item\" text"</string>
Yeni dilləri tərcÃŧmə etmək ÃŧçÃŧn translate.revanced.app 'ə daxil olun"</string>
<string name="revanced_language_DEFAULT">Tətbiq dili</string>
<string name="revanced_language_AR">Ərəbcə</string>
<string name="revanced_language_AZ">Azərbaycanca</string>
<string name="revanced_language_BG">Bolqarca</string>
<string name="revanced_language_BN">Benqalca</string>
<string name="revanced_language_CA">Katalan dili</string>
<string name="revanced_language_CS">Çexcə</string>
<string name="revanced_language_DA">Dan dili</string>
<string name="revanced_language_DE">Almanca</string>
<string name="revanced_language_EL">Yunanca</string>
<string name="revanced_language_EN">İngiliscə</string>
<string name="revanced_language_ES">İspanca</string>
<string name="revanced_language_ET">Estonca</string>
<string name="revanced_language_FA">Farsca</string>
<string name="revanced_language_FI">Fincə</string>
<string name="revanced_language_FR">FransÄązca</string>
<string name="revanced_language_GU">QÃŧcərat dili</string>
<string name="revanced_language_HI">Hindcə</string>
<string name="revanced_language_HR">Xorvatca</string>
<string name="revanced_language_HU">Macarca</string>
<string name="revanced_language_ID">İndoneziya dili</string>
<string name="revanced_language_IT">İtalyanca</string>
<string name="revanced_language_JA">Yaponca</string>
<string name="revanced_language_KK">Qazax dili</string>
<string name="revanced_language_KO">Koreya dili</string>
<string name="revanced_language_LT">Litva Dili</string>
<string name="revanced_language_LV">Letonca</string>
<string name="revanced_language_MK">Makedon Dili</string>
<string name="revanced_language_MN">Monqolca</string>
<string name="revanced_language_MR">Marathi dili</string>
<string name="revanced_language_MS">Malay dili</string>
<string name="revanced_language_MY">Birmanca</string>
<string name="revanced_language_NL">Hollandca</string>
<string name="revanced_language_OR">Oriya dili</string>
<string name="revanced_language_PA">Pəncabca</string>
<string name="revanced_language_PL">Polyak dili</string>
<string name="revanced_language_PT">Portuqal dili</string>
<string name="revanced_language_RO">RumÄąnca</string>
<string name="revanced_language_RU">Rusca</string>
<string name="revanced_language_SK">Slovak dili</string>
<string name="revanced_language_SL">Slovencə</string>
<string name="revanced_language_SR">Serbcə</string>
<string name="revanced_language_SV">İsveçcə</string>
<string name="revanced_language_SW">Suahili dili</string>
<string name="revanced_language_TA">Tamilcə</string>
<string name="revanced_language_TE">Teluqu dili</string>
<string name="revanced_language_TH">Tayca</string>
<string name="revanced_language_TR">TÃŧrkcə</string>
<string name="revanced_language_UK">Ukrayna dili</string>
<string name="revanced_language_UR">Urdu dili</string>
<string name="revanced_language_VI">Vyetnamca</string>
<string name="revanced_language_ZH">Çincə</string>
<string name="revanced_pref_import_export_title">İdxal/İxrac et</string>
<string name="revanced_pref_import_export_summary">ReVanced tənzimləmələrin idxal/ixrac et</string>
<!-- Settings about dialog. -->
@@ -278,12 +227,12 @@ GÃļzlənilməz hallardan xəbərdar olmayacaqsÄąnÄąz."</string>
<string name="revanced_hide_artist_cards_summary_on">Sənətçi kartlarÄą gizlidir</string>
<string name="revanced_hide_artist_cards_summary_off">Sənətçi kartlarÄą gÃļstərilir</string>
<string name="revanced_hide_attributes_section_title">Atributları Gizlət</string>
<string name="revanced_hide_attributes_section_summary_on">Seçilən məkanlar, Oyunlar, Musiqi və qeyd edilən insanlar bÃļlmələri gizlədilir</string>
<string name="revanced_hide_attributes_section_summary_off">Seçilən məkanlar, Oyunlar, Musiqi və qeyd edilən insanlar bÃļlmələri gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_attributes_section_summary_on">Seçilən yerlər, Oyunlar, Musiqi və qeyd edilən insanlar bÃļlmələri gizlədilir</string>
<string name="revanced_hide_attributes_section_summary_off">Seçilən yerlər, Oyunlar, Musiqi və qeyd edilən insanlar bÃļlmələri gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_chapters_section_title">Fəsilləri Gizlət</string>
<string name="revanced_hide_chapters_section_summary_on">BÃļlÃŧmlər bÃļlməsi gizlidir</string>
<string name="revanced_hide_chapters_section_summary_off">BÃļlÃŧmlər bÃļlməsi gÃļstərilir</string>
<string name="revanced_hide_how_this_was_made_section_title">\'Bu məzmun necə hazırlanıb\'ı Gizlət</string>
<string name="revanced_hide_how_this_was_made_section_title">\'Bu kontent necə hazırlanıb\'ı Gizlət</string>
<string name="revanced_hide_how_this_was_made_section_summary_on">Bu məzmunun necə hazÄąrlandığı bÃļlməsi gizlidir</string>
<string name="revanced_hide_how_this_was_made_section_summary_off">Bu məzmunun necə hazÄąrlandığı bÃļlməsi gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_podcast_section_title">\'PodkastÄą araşdÄąrÄąn\"-Äą Gizlət</string>
@@ -292,14 +241,14 @@ GÃļzlənilməz hallardan xəbərdar olmayacaqsÄąnÄąz."</string>
<string name="revanced_hide_info_cards_section_title">Məlumat Kartlarını Gizlət</string>
<string name="revanced_hide_info_cards_section_summary_on">Məlumat kartlarÄą bÃļlməsi gizlədilir</string>
<string name="revanced_hide_info_cards_section_summary_off">Məlumat kartlarÄą bÃļlməsi gÃļstərilir</string>
<string name="revanced_hide_key_concepts_section_title">\"Əsas anlayÄąÅŸlarÄą\" gizlət</string>
<string name="revanced_hide_key_concepts_section_summary_on">Əsas anlayÄąÅŸlar bÃļlməsi gizlidir</string>
<string name="revanced_hide_key_concepts_section_summary_off">Əsas anlayÄąÅŸlar bÃļlməsi gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_key_concepts_section_title">\"Əsas konseptlər-i\" gizlət</string>
<string name="revanced_hide_key_concepts_section_summary_on">Əsas konseptlər bÃļlməsi gizlidir</string>
<string name="revanced_hide_key_concepts_section_summary_off">Əsas konseptlər bÃļlməsi gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_transcript_section_title">Transkript-i Gizlət</string>
<string name="revanced_hide_transcript_section_summary_on">Transkripsiya bÃļlməsi gizlidir</string>
<string name="revanced_hide_transcript_section_summary_off">Transkripsiya bÃļlməsi gÃļstərilir</string>
<string name="revanced_hide_description_components_screen_title">Video aÃ§ÄąqlamasÄą</string>
<string name="revanced_hide_description_components_screen_summary">Video aÃ§ÄąqlamasÄą elementlərini gizlət və ya gÃļstər</string>
<string name="revanced_hide_description_components_screen_title">Video təsviri</string>
<string name="revanced_hide_description_components_screen_summary">Video təsviri elementlərini gizlət və ya gÃļstər</string>
<string name="revanced_hide_filter_bar_screen_title">Filtr çubuğu</string>
<string name="revanced_hide_filter_bar_screen_summary">AxÄąnda, axtarÄąÅŸ nəticələrində və əlaqəli videolarda filtr cərgəsin gizlət və ya gÃļstər</string>
<string name="revanced_hide_filter_bar_feed_in_feed_title">Axında gizlət</string>
@@ -313,9 +262,8 @@ GÃļzlənilməz hallardan xəbərdar olmayacaqsÄąnÄąz."</string>
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">Əlaqəli videolarda gÃļrÃŧnÃŧr</string>
<string name="revanced_comments_screen_title">Şərhlər</string>
<string name="revanced_comments_screen_summary">Şərhlər bÃļlməsi elementlərin gizlət və ya gÃļstər</string>
<string name="revanced_hide_comments_chat_summary_title">\'SÃļhbət yekunun\' Gizlət</string>
<string name="revanced_hide_comments_chat_summary_summary_on">SÃļhbət yekunu gizlidir </string>
<string name="revanced_hide_comments_chat_summary_summary_off">SÃļhbət yekunu gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">SÃļhbət yekunu gizlidir </string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">SÃļhbət yekunu gÃļrÃŧnÃŧr</string>
<string name="revanced_hide_comments_by_members_header_title">\'Üzvlərin şərhləri\' başlığınÄą gizlət</string>
<string name="revanced_hide_comments_by_members_header_summary_on">Üzvlərin şərhləri başlığı gizlidir</string>
<string name="revanced_hide_comments_by_members_header_summary_off">Üzvlərin şərhləri başlığı gÃļrÃŧnÃŧr</string>
@@ -362,7 +310,7 @@ GÃļzlənilməz hallardan xəbərdar olmayacaqsÄąnÄąz."</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_on">Abunəliklər bÃļlməsindəki videolar açar sÃļzlərlə filtrlənir</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_off">Abunəliklər bÃļlməsindəki videolar açar sÃļzlərlə filtrlənmir</string>
<string name="revanced_hide_keyword_content_phrases_title">Gizlədiləcək açar sÃļzlər</string>
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<string name="revanced_hide_keyword_content_phrases_summary">"Yeni sətirlərlə ayrÄąlan, gizlədiləcək açar sÃļzlər və ifadələr
@@ -377,7 +325,7 @@ Məhdudiyyətlər
â€ĸ Bəzi UI hissəcikləri gizlənə bilməz
â€ĸ Açar sÃļz axtarma nəticə verməyə bilər"</string>
<string name="revanced_hide_keyword_content_about_whole_words_title">BÃŧtÃŧn sÃļzləri uyğunlaşdÄąr</string>
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<string name="revanced_hide_keyword_content_about_whole_words_summary">Açar sÃļz/frazanÄąn qoşa dÄąrnaqlarla əhatə olunmasÄą video adlarÄą və kanal adlarÄąnÄąn qismən uyğunlaşmasÄąna mane olacaq &lt;br&gt;&lt;br&gt;Məsələn,&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt; videonu gizlədəcək:&lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt; lakin gizlətməyəcək: DÃŧzgÃŧn;&lt;b&gt;What does fair use mean?&lt;/b&gt;</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="revanced_hide_keyword_toast_invalid_common">Açar sÃļz istifadə edilə bilmir: %s</string>
@@ -404,7 +352,7 @@ Bu xÃŧsusiyyət yalnÄąz kÃļhnə cihazlar ÃŧçÃŧn mÃļvcuddur"</string>
<string name="revanced_hide_self_sponsor_ads_title">Öz-sponsorlu kartlarÄą gizlət</string>
<string name="revanced_hide_self_sponsor_ads_summary_on">ÖzÃŧnə sponsorluq edilən kartlar gizlidir</string>
<string name="revanced_hide_self_sponsor_ads_summary_off">ÖzÃŧnə sponsorluq edilən kartlar gÃļstərilir</string>
<string name="revanced_hide_products_banner_title">Məhsullara baxma etiketin gizlət</string>
<string name="revanced_hide_products_banner_title">\"Məhsullara baxın\" etiketin gizlət</string>
<string name="revanced_hide_products_banner_summary_on">Etiket gizlədilib</string>
<string name="revanced_hide_products_banner_summary_off">Etiket gÃļstərilir</string>
<string name="revanced_hide_end_screen_store_banner_title">Son ekran mağaza etiketini gizlət</string>
@@ -475,9 +423,6 @@ Bu xÃŧsusiyyət yalnÄąz kÃļhnə cihazlar ÃŧçÃŧn mÃļvcuddur"</string>
<string name="revanced_disable_precise_seeking_gesture_summary_off">Jest aktivləşdirilib</string>
</patch>
<patch id="interaction.seekbar.enableSeekbarTappingPatch">
<string name="revanced_seekbar_tapping_title">İrəliləmə cizgisi toxunmasÄąnÄą aktivləşdir</string>
<string name="revanced_seekbar_tapping_summary_on">İrəliləyiş cizgisi toxunmasÄą aktivdir</string>
<string name="revanced_seekbar_tapping_summary_off">İrəliləyiş cizgisi toxunmasÄą qapalÄądÄąr</string>
</patch>
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
<string name="revanced_swipe_brightness_title">ParlaqlÄąq jestini aktivləşdir</string>
@@ -490,9 +435,6 @@ EkranÄąn sol tərəfində dikinə sÃŧrÃŧşdÃŧrərək parlaqlığı tənzimləyin
EkranÄąn sağ tərəfində dÃŧzÃŧnə sÃŧrÃŧşdÃŧrərək səs səviyyəsini tənzimlə"</string>
<string name="revanced_swipe_volume_summary_off">Tam ekran səs sÃŧrÃŧşdÃŧrməsi qapalÄądÄąr</string>
<string name="revanced_swipe_press_to_engage_title">BasÄąb sÃŧrÃŧşdÃŧrmə jestini aktivləşdir</string>
<string name="revanced_swipe_press_to_engage_summary_on">SÃŧrÃŧşdÃŧrmək ÃŧçÃŧn basma aktivdir</string>
<string name="revanced_swipe_press_to_engage_summary_off">SÃŧrÃŧşdÃŧrmək ÃŧçÃŧn basma qeyri-aktivdir</string>
<string name="revanced_swipe_haptic_feedback_title">Əks-əlaqə reaksiyasÄąnÄą aktivləşdir</string>
<string name="revanced_swipe_haptic_feedback_summary_on">Əks-əlaqə reaksiyasÄą aktivləşdirilib</string>
<string name="revanced_swipe_haptic_feedback_summary_off">Əks-əlaqə reaksiyasÄą qeyri-aktivdir</string>
@@ -663,7 +605,7 @@ Bu seçimi dəyişdirmə işə dÃŧşmÃŧrsə, Gizli rejimə keçməyə çalÄąÅŸÄą
<string name="revanced_hide_player_flyout_video_quality_footer_summary_off">Video keyfiyyət menyusu alt məlumatÄą gÃļstərilir</string>
</patch>
<patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch">
<string name="revanced_hide_player_previous_next_buttons_title">Əvvəlki/nÃļvbəti video dÃŧymələrin gizlət</string>
<string name="revanced_hide_player_previous_next_buttons_title">Əvvəlki və NÃļvbəti dÃŧymələrin gizlət</string>
<string name="revanced_hide_player_previous_next_buttons_summary_on">DÃŧymələr gizlidir</string>
<string name="revanced_hide_player_previous_next_buttons_summary_off">DÃŧymələr gÃļstərilir</string>
<string name="revanced_hide_cast_button_title">YayÄąmla dÃŧyməsini gizlət</string>
@@ -855,7 +797,6 @@ Avtomatik oynatma YouTube ayarlarÄąnda dəyişdirilə bilər: Ayarlar → Oxunu
<string name="revanced_ryd_enable_summary_on">Bəyənməmələr gÃļstərilir</string>
<string name="revanced_ryd_enable_summary_off">Bəyənməmələr gÃļstərilmir</string>
<string name="revanced_ryd_shorts_title">\"Shorts\"da bəyənməmə sayÄąnÄą gÃļstər</string>
<string name="revanced_ryd_shorts_summary_on">Bəyənməmələr Shorts-da gÃļstərilir</string>
<string name="revanced_ryd_shorts_summary_on_disclaimer">"Bəyənməmələr Shorts-da gÃļstərilir
Məhdudiyyət: Bəyənməmələr gizli rejimdə gÃļrÃŧnməyə bilər"</string>
@@ -1053,6 +994,8 @@ ArtÄąq mÃļvcuddur"</string>
<string name="revanced_sb_vote_downvote">Mənfi səs</string>
<string name="revanced_sb_vote_category">KateqoriyanÄą dəyişdir</string>
<string name="revanced_sb_vote_no_segments">Səsvermə ÃŧçÃŧn bÃļlÃŧm yoxdur</string>
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<string name="revanced_sb_vote_segment_time_to_from">%1$s - %2$s</string>
<string name="revanced_sb_new_segment_choose_category">BÃļlÃŧm kateqoriyasÄąnÄą seçin</string>
<string name="revanced_sb_new_segment_disabled_category">Seçimlərdə kateqoriya qeyri-aktivdir. GÃļndərmək ÃŧçÃŧn kateqoriyanÄą aktiv et.</string>
<string name="revanced_sb_new_segment_title">Yeni SponsorBlock bÃļlÃŧmÃŧ</string>
@@ -1100,6 +1043,7 @@ Təqdim etməyə hazırdır?"</string>
<string name="revanced_sb_stats_saved_hour_format">%1$s saat %2$s dəqiqə</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s dəqiqə %2$s saniyə</string>
<string name="revanced_sb_stats_saved_second_format">%s saniyə</string>
<string name="revanced_sb_color_opacity_label">Qeyri-şəffaflÄąq:</string>
<string name="revanced_sb_color_dot_label">Rəng:</string>
<string name="revanced_sb_color_changed">Rəng dəyişdirildi</string>
<string name="revanced_sb_color_reset">Rəngi sıfırla</string>
@@ -1115,16 +1059,14 @@ Təqdim etməyə hazırdır?"</string>
<string name="revanced_change_form_factor_entry_2">Telefon</string>
<string name="revanced_change_form_factor_entry_3">Planşet</string>
<string name="revanced_change_form_factor_entry_4">Avtomobil</string>
<string name="revanced_change_form_factor_user_dialog_message">"Dəyişikliklərə daxildir:
<string name="revanced_change_form_factor_user_dialog_message">"Dəyişikliklər ehtiva edir:
Planşet tərtibatÄą
â€ĸ İcma elanlarÄą gizlidir
â€ĸ İcma elanlarÄą gizlədilib
Avtomobil tərtibatı
â€ĸ BaxÄąÅŸ tarixçəsi seçimi gizlidir
â€ĸ \"Kəşf et\" bÃļlməsi qaytarÄąlÄąb
â€ĸ Shorts daimi oynadÄącÄąda aÃ§ÄąlÄąr
â€ĸ AxÄąn mÃļvzulara və kanala gÃļrə hazÄąrlanÄąb"</string>
â€ĸ Shorts mÃŧntəzəm oynadÄącÄąda aÃ§ÄąlÄąr
â€ĸ AxÄąn mÃļvzular və kanallardan ibarətdir"</string>
</patch>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<string name="revanced_spoof_app_version_title">Tətbiq versiyasÄąnÄą saxtalaşdÄąr</string>
@@ -1139,12 +1081,7 @@ Sonradan qapadÄąlarsa, UI səhvlərin Ãļnləmək ÃŧçÃŧn tətbiq məlumatlarÄąn
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<string name="revanced_spoof_app_version_target_title">Saxta tətbiq versiyası hədəfi</string>
<string name="revanced_spoof_app_version_target_entry_1">19.35.36 - KÃļhnə Shorts oynadÄącÄą işarələrin bərpa et</string>
<string name="revanced_spoof_app_version_target_entry_2">19.26.42 - KÃļhnə fəaliyyət simvollarÄąn bərpa et</string>
<!-- 'RYD' is 'Return YouTube Dislike' -->
<string name="revanced_spoof_app_version_target_legacy_entry_1">18.33.40 - Shorts gizli rejimində RYD-ni bərpa et</string>
<string name="revanced_spoof_app_version_target_legacy_entry_2">18.20.39 - Geniş video sÃŧrəti &amp; keyfiyyət menyusunu bərpa et</string>
<string name="revanced_spoof_app_version_target_legacy_entry_3">18.09.39 - Kitabxana panelini bərpa et</string>
<string name="revanced_spoof_app_version_target_legacy_entry_4">17.33.42 - KÃļhnə pleylist bÃļlməsin bərpa et</string>
<string name="revanced_spoof_app_version_target_entry_2">19.01.34 - KÃļhnə fəaliyyət simvollarÄąn bərpa et</string>
</patch>
<patch id="layout.startpage.changeStartPagePatch">
<string name="revanced_change_start_page_title">Başlanğıc səhifəsini təyin et</string>
@@ -1194,7 +1131,7 @@ Sonradan qapadÄąlarsa, UI səhvlərin Ãļnləmək ÃŧçÃŧn tətbiq məlumatlarÄąn
</patch>
<patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">Kiçik oynadÄącÄą</string>
<string name="revanced_miniplayer_screen_summary">Tətbiqdə kiçildilən oynadÄącÄą Ãŧslubunu dəyişdir</string>
<string name="revanced_miniplayer_screen_summary">Tətbiqdaxili kiçilən oynadÄącÄą Ãŧslubunu dəyişdir</string>
<string name="revanced_miniplayer_type_title">Kiçik oynadÄącÄą nÃļvÃŧ</string>
<string name="revanced_miniplayer_type_entry_0">Qeyri-aktivdir</string>
<string name="revanced_miniplayer_type_entry_1">İlkin</string>
@@ -1247,8 +1184,6 @@ Genişləndirmək və ya bağlamaq ÃŧçÃŧn sÃŧrÃŧşdÃŧr"</string>
<string name="revanced_gradient_loading_screen_title">Dəyişkən yÃŧkləmə ekranÄąnÄą aktivləşdir</string>
<string name="revanced_gradient_loading_screen_summary_on">YÃŧkləmə ekranÄą, dəyişkən arxa plana malik olacaq</string>
<string name="revanced_gradient_loading_screen_summary_off">YÃŧkləmə ekranÄą, vahid arxa plana malik olacaq</string>
</patch>
<patch id="layout.theme.themeResourcePatch">
<string name="revanced_seekbar_custom_color_title">Fərdi irəliləmə cizgisi rəngini aktivləşdir</string>
<string name="revanced_seekbar_custom_color_summary_on">Fərdi irəliləmə cizgisi rəngi gÃļstərilir</string>
<string name="revanced_seekbar_custom_color_summary_off">Orijinal irəliləmə cizgisi rəngi gÃļstərilir</string>
@@ -1340,8 +1275,8 @@ Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər
</patch>
<patch id="misc.links.openLinksExternallyPatch">
<string name="revanced_external_browser_title">BağlantÄąlarÄą brauzerdə aç</string>
<string name="revanced_external_browser_summary_on">BağlantÄąlar xarici yolla aÃ§ÄąlÄąr</string>
<string name="revanced_external_browser_summary_off">BağlantÄąlar tətbiqdə aÃ§ÄąlÄąr</string>
<string name="revanced_external_browser_summary_on">Xarici brauzerdə bağlantÄąlarÄąn aÃ§ÄąlmasÄą</string>
<string name="revanced_external_browser_summary_off">Tətbiqdaxili brauzerdə bağlantÄąlarÄąn aÃ§ÄąlmasÄą</string>
</patch>
<patch id="misc.privacy.removeTrackingQueryParameterPatch">
<string name="revanced_remove_tracking_query_parameter_title">İzləmə sorğusu faktorun sil</string>
@@ -1368,9 +1303,15 @@ Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər
<string name="revanced_remember_video_quality_last_selected_summary_off">Keyfiyyət dəyişiklikləri yalnÄąz cari videoya tətbiq edilir</string>
<string name="revanced_video_quality_default_wifi_title">Wi-Fi şəbəkəsində ilkin video keyfiyyəti</string>
<string name="revanced_video_quality_default_mobile_title">Mobil şəbəkədə ilkin video keyfiyyəti</string>
<string name="revanced_remember_shorts_quality_last_selected_title">Shorts keyfiyyət dəyişikliklərini xatÄąrla</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">Keyfiyyət dəyişiklikləri bÃŧtÃŧn Shorts-a tətbiq edilir</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">Keyfiyyət dəyişiklikləri yalnÄąz cari Short-a tətbiq edilir</string>
<string name="revanced_shorts_quality_default_wifi_title">Wi-Fi şəbəkəsində ilkin Shorts keyfiyyəti</string>
<string name="revanced_shorts_quality_default_mobile_title">Mobil şəbəkədə ilkin Shorts keyfiyyəti</string>
<string name="revanced_remember_video_quality_mobile">mobil</string>
<string name="revanced_remember_video_quality_wifi">wi-fi</string>
<string name="revanced_remember_video_quality_toast">İlkin %1$s keyfiyyəti %2$s kimi dəyişdi</string>
<string name="revanced_remember_video_quality_toast_shorts">Shorts-un %1$s keyfiyyəti %2$s olaraq dəyişdirildi</string>
</patch>
<patch id="video.speed.button.playbackSpeedButtonPatch">
<string name="revanced_playback_speed_dialog_button_title">SÃŧrət dialoq dÃŧyməsini gÃļstər</string>
@@ -1401,10 +1342,10 @@ Bunu aktivləşdirmə daha yÃŧksək video keyfiyyətləri əngəlin silə bilər
<string name="revanced_disable_hdr_video_summary_on">HDR video qapalÄądÄąr</string>
<string name="revanced_disable_hdr_video_summary_off">HDR video aktivdir</string>
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<string name="revanced_restore_old_video_quality_menu_title">KÃļhnə video keyfiyyət menusun qaytar</string>
<string name="revanced_restore_old_video_quality_menu_summary_on">KÃļhnə video keyfiyyət siyahÄąsÄą gÃļstərilir</string>
<string name="revanced_restore_old_video_quality_menu_summary_off">KÃļhnə video keyfiyyət siyahÄąsÄą gÃļrÃŧnmÃŧr</string>
<patch id="video.quality.advancedVideoQualityMenuPatch">
<string name="revanced_advanced_video_quality_menu_title">QabaqcÄąl video keyfiyyət siyahÄąsÄąn gÃļstər</string>
<string name="revanced_advanced_video_quality_menu_summary_on">QabaqcÄąl video keyfiyyət siyahÄąsÄą gÃļstərilir</string>
<string name="revanced_advanced_video_quality_menu_summary_off">QabaqcÄąl video keyfiyyət siyahÄąsÄą gÃļstərilmir</string>
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
<string name="revanced_slide_to_seek_title">Axtarmaq ÃŧçÃŧn sÃŧrÃŧşdÃŧrməni aktiv et</string>

View File

@@ -48,57 +48,6 @@ Second \"item\" text"</string>
Каб Đ´Đ°Đ´Đ°Ņ†ŅŒ ĐŊĐžĐ˛Ņ‹Ņ ĐŧĐžĐ˛Ņ‹, ĐŊавĐĩĐ´Đ°ĐšŅ†Đĩ translate.revanced.app"</string>
<string name="revanced_language_DEFAULT">Мова ĐŋŅ€Đ°ĐŗŅ€Đ°ĐŧŅ‹</string>
<string name="revanced_language_AR">ĐŅ€Đ°ĐąŅĐēĐ°Ņ</string>
<string name="revanced_language_AZ">АСĐĩŅ€ĐąĐ°ĐšĐ´ĐļаĐŊҁĐēŅ–</string>
<string name="revanced_language_BG">БаĐģĐŗĐ°Ņ€ŅĐēĐ°Ņ</string>
<string name="revanced_language_BN">БĐĩĐŊĐŗĐ°ĐģҌҁĐēĐ°Ņ</string>
<string name="revanced_language_CA">ĐšĐ°Ņ‚Đ°ĐģĐžĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_CS">Đ§ŅŅˆŅĐēŅ–</string>
<string name="revanced_language_DA">Đ”Đ°Ņ†ĐēŅ–</string>
<string name="revanced_language_DE">ĐŅĐŧĐĩ҆ĐēŅ–</string>
<string name="revanced_language_EL">Đ“Ņ€ŅŅ†ĐēŅ–</string>
<string name="revanced_language_EN">АĐŊĐŗĐģŅ–ĐšŅĐēĐ°Ņ</string>
<string name="revanced_language_ES">Đ†ŅĐŋаĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_ET">Đ­ŅŅ‚ĐžĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_FA">ПĐĩŅ€ŅŅ–Đ´ŅĐēĐ°Ņ</string>
<string name="revanced_language_FI">Đ¤Ņ–ĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_FR">Đ¤Ņ€Đ°ĐŊŅ†ŅƒĐˇŅĐēĐ°Ņ</string>
<string name="revanced_language_GU">Đ“ŅƒĐ´ĐļĐ°Ņ€Đ°Ņ†Ņ–</string>
<string name="revanced_language_HI">ĐĨŅ–ĐŊĐ´ĐˇŅ–</string>
<string name="revanced_language_HR">ĐĨĐ°Ņ€Đ˛Đ°Ņ†ĐēĐ°Ņ</string>
<string name="revanced_language_HU">ВĐĩĐŊĐŗĐĩҀҁĐēĐ°Ņ</string>
<string name="revanced_language_ID">ІĐŊдаĐŊĐĩĐˇŅ–ĐšŅĐēĐ°Ņ</string>
<string name="revanced_language_IT">Đ†Ņ‚Đ°ĐģŅŒŅĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_JA">Đ¯ĐŋĐžĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_KK">ĐšĐ°ĐˇĐ°Ņ…ŅĐēĐ°Ņ</string>
<string name="revanced_language_KO">ĐšĐ°Ņ€ŅĐšŅĐēĐ°Ņ</string>
<string name="revanced_language_LT">Đ›Ņ–Ņ‚ĐžŅžŅĐēĐ°Ņ</string>
<string name="revanced_language_LV">Đ›Đ°Ņ‚Ņ‹ŅˆŅĐēĐ°Ņ</string>
<string name="revanced_language_MK">МаĐēĐĩĐ´ĐžĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_MN">МаĐŊĐŗĐžĐģҌҁĐēĐ°Ņ</string>
<string name="revanced_language_MR">МаĐģĐ°ŅĐģаĐŧ</string>
<string name="revanced_language_MS">МаĐģĐ°ĐšŅĐēĐ°Ņ</string>
<string name="revanced_language_MY">Đ‘Ņ–Ņ€ĐŧаĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_NL">ĐŅ–Đ´ŅŅ€ĐģаĐŊĐ´ŅĐēĐ°Ņ</string>
<string name="revanced_language_OR">ĐžĐ´Ņ‹Ņ</string>
<string name="revanced_language_PA">ПĐĩĐŊĐ´ĐļĐ°ĐąŅ–</string>
<string name="revanced_language_PL">ПоĐģҌҁĐēĐ°Ņ</string>
<string name="revanced_language_PT">ĐŸĐ°Ņ€Ņ‚ŅƒĐŗĐ°ĐģҌҁĐēĐ°Ņ</string>
<string name="revanced_language_RO">Đ ŅƒĐŧŅ‹ĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_RU">Đ ŅƒŅĐēĐ°Ņ</string>
<string name="revanced_language_SK">ĐĄĐģĐ°Đ˛Đ°Ņ†ĐēĐ°Ņ</string>
<string name="revanced_language_SL">ĐĄĐģавĐĩĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_SR">ĐĄĐĩŅ€ĐąŅĐēĐ°Ņ</string>
<string name="revanced_language_SV">ШвĐĩĐ´ŅĐēĐ°Ņ</string>
<string name="revanced_language_SW">ĐĄŅƒĐ°Ņ…Ņ–ĐģŅ–</string>
<string name="revanced_language_TA">ĐĸаĐŧŅ–ĐģҌҁĐēĐ°Ņ</string>
<string name="revanced_language_TE">ĐĸŅĐģŅƒĐŗŅƒ</string>
<string name="revanced_language_TH">ĐĸĐ°ĐšŅĐēĐ°Ņ</string>
<string name="revanced_language_TR">ĐĸŅƒŅ€Đĩ҆ĐēĐ°Ņ</string>
<string name="revanced_language_UK">ĐŖĐēŅ€Đ°Ņ–ĐŊҁĐēĐ°Ņ</string>
<string name="revanced_language_UR">ĐŖŅ€Đ´Ņƒ</string>
<string name="revanced_language_VI">В\'ĐĩŅ‚ĐŊаĐŧҁĐēĐ°Ņ</string>
<string name="revanced_language_ZH">ĐšŅ–Ņ‚Đ°ĐšŅĐēĐ°Ņ</string>
<string name="revanced_pref_import_export_title">ІĐŧĐŋĐ°Ņ€Ņ‚ / Đ­ĐēҁĐŋĐ°Ņ€Ņ‚</string>
<string name="revanced_pref_import_export_summary">ІĐŧĐŋĐ°Ņ€Ņ‚ / Đ­ĐēҁĐŋĐ°Ņ€Ņ‚ ĐŊаĐģад ReVanced</string>
<!-- Settings about dialog. -->
@@ -277,6 +226,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_artist_cards_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐ°Ņ€Ņ‚ĐēŅ– Đ˛Ņ‹ĐēаĐŊĐ°ŅžŅ†Đ°Ņž</string>
<string name="revanced_hide_artist_cards_summary_on">ĐšĐ°Ņ€Ņ‚ĐēŅ– Đ˛Ņ‹ĐēаĐŊĐ°ŅžŅ†Đ°Ņž ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹Ņ</string>
<string name="revanced_hide_artist_cards_summary_off">ПаĐēĐ°ĐˇĐ˛Đ°ŅŽŅ†Ņ†Đ° ĐēĐ°Ņ€Ņ‚ĐēŅ– Đ˛Ņ‹ĐēаĐŊĐ°ŅžŅ†Đ°Ņž</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ÂĢЗводĐē҃ Đ˛Ņ–Đ´ŅĐ°, ĐˇĐŗĐĩĐŊŅŅ€Đ°Đ˛Đ°ĐŊŅƒŅŽ ŅˆŅ‚ŅƒŅ‡ĐŊŅ‹Đŧ Ņ–ĐŊŅ‚ŅĐģĐĩĐēŅ‚Đ°ĐŧÂģ</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">РаСдСĐĩĐģ СвОдĐēŅ– Đ˛Ņ–Đ´ŅĐ° ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">РаСдСĐĩĐģ СвОдĐēŅ– Đ˛Ņ–Đ´ŅĐ° ĐŋаĐēаСаĐŊŅ‹</string>
<string name="revanced_hide_attributes_section_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ Đ°Ņ‚Ņ€Ņ‹ĐąŅƒŅ‚Ņ‹</string>
<string name="revanced_hide_attributes_section_summary_on">РаСдСĐĩĐģŅ‹ ÂĢПаĐŋ҃ĐģŅŅ€ĐŊŅ‹Ņ ĐŧĐĩҁ҆ҋÂģ, ÂĢĐ“ŅƒĐģҌĐŊŅ–Âģ, ÂĢĐœŅƒĐˇŅ‹ĐēаÂģ Ņ– ÂĢĐ›ŅŽĐ´ĐˇŅ–, ŅĐēŅ–Ņ… ĐˇĐŗĐ°Đ´Đ˛Đ°ĐģŅ–Âģ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹Ņ</string>
<string name="revanced_hide_attributes_section_summary_off">РаСдСĐĩĐģŅ‹ ÂĢПаĐŋ҃ĐģŅŅ€ĐŊŅ‹Ņ ĐŧĐĩҁ҆ҋÂģ, ÂĢĐ“ŅƒĐģҌĐŊŅ–Âģ, ÂĢĐœŅƒĐˇŅ‹ĐēаÂģ Ņ– ÂĢĐ›ŅŽĐ´ĐˇŅ–, ŅĐēŅ–Ņ… ĐˇĐŗĐ°Đ´Đ˛Đ°ĐģŅ–Âģ ĐŋаĐēаСаĐŊŅ‹Ņ</string>
@@ -313,9 +265,12 @@ Second \"item\" text"</string>
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">ПаĐēаСаĐŊа Ņž ĐˇĐ˛ŅĐˇĐ°ĐŊҋ҅ Đ˛Ņ–Đ´ŅĐ°</string>
<string name="revanced_comments_screen_title">КаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹Ņ–</string>
<string name="revanced_comments_screen_summary">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ айО ĐŋаĐēĐ°ĐˇĐ°Ņ†ŅŒ ĐēаĐŧĐŋаĐŊĐĩĐŊ҂ҋ Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģа ĐēаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹ŅŅž</string>
<string name="revanced_hide_comments_chat_summary_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ÂĢЗводĐē҃ Ņ‡Đ°Ņ‚Đ°Âģ</string>
<string name="revanced_hide_comments_chat_summary_summary_on">ЗводĐēа Ņ‡Đ°Ņ‚Đ° ŅŅ…Đ°Đ˛Đ°ĐŊĐ°Ņ</string>
<string name="revanced_hide_comments_chat_summary_summary_off">ЗводĐēа Ņ‡Đ°Ņ‚Đ° ĐŋаĐēаСаĐŊĐ°Ņ</string>
<string name="revanced_hide_comments_ai_chat_summary_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ СвОдĐē҃ Ņ‡Đ°Ņ‚Đ° ŅĐ° ŅˆŅ‚ŅƒŅ‡ĐŊŅ‹Đŧ Ņ–ĐŊŅ‚ŅĐģĐĩĐēŅ‚Đ°Đŧ</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">ЗводĐēа Ņ‡Đ°Ņ‚Đ° ŅŅ…Đ°Đ˛Đ°ĐŊĐ°Ņ</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">ЗводĐēа Ņ‡Đ°Ņ‚Đ° ĐŋаĐēаСаĐŊĐ°Ņ</string>
<string name="revanced_hide_comments_ai_summary_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ СвОдĐē҃ ĐēаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹ŅŅž ŅĐ° ŅˆŅ‚ŅƒŅ‡ĐŊŅ‹Đŧ Ņ–ĐŊŅ‚ŅĐģĐĩĐēŅ‚Đ°Đŧ</string>
<string name="revanced_hide_comments_ai_summary_summary_on">ЗводĐēа ĐēаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹ŅŅž ŅŅ…Đ°Đ˛Đ°ĐŊĐ°Ņ</string>
<string name="revanced_hide_comments_ai_summary_summary_off">ЗводĐēа ĐēаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹ŅŅž ĐŋаĐēаСаĐŊĐ°Ņ</string>
<string name="revanced_hide_comments_by_members_header_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐˇĐ°ĐŗĐ°ĐģОваĐē \"КаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹Ņ– ŅžĐ´ĐˇĐĩĐģҌĐŊŅ–ĐēĐ°Ņž\"</string>
<string name="revanced_hide_comments_by_members_header_summary_on">Đ—Đ°ĐŗĐ°ĐģОваĐē ÂĢКаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹ ŅžĐ´ĐˇĐĩĐģҌĐŊŅ–ĐēĐ°ŅžÂģ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_hide_comments_by_members_header_summary_off">Đ—Đ°ĐŗĐ°ĐģОваĐē ÂĢКаĐŧĐĩĐŊŅ‚Đ°Ņ€Ņ‹ ŅžĐ´ĐˇĐĩĐģҌĐŊŅ–ĐēĐ°ŅžÂģ ĐŋаĐēаСаĐŊŅ‹</string>
@@ -362,7 +317,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_on">Đ’Ņ–Đ´ŅĐ° ва ŅžĐēĐģĐ°Đ´Ņ†Ņ‹ ÂĢПадĐŋҖҁĐēŅ–Âģ ҄ҖĐģŅŒŅ‚Ņ€ŅƒŅŽŅ†Ņ†Đ° Đŋа ĐēĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ… ҁĐģĐžĐ˛Đ°Ņ…</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_off">Đ’Ņ–Đ´ŅĐ° ва ŅžĐēĐģĐ°Đ´Ņ†Ņ‹ \"ПадĐŋҖҁĐēŅ–\" ĐŊĐĩ ҄ҖĐģŅŒŅ‚Ņ€ŅƒŅŽŅ†Ņ†Đ° Đŋа ĐēĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ… ҁĐģĐžĐ˛Đ°Ņ…</string>
<string name="revanced_hide_keyword_content_phrases_title">КĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ ҁĐģĐžĐ˛Ņ‹, ŅĐēŅ–Ņ Ņ‚Ņ€ŅĐąĐ° ŅŅ…Đ°Đ˛Đ°Ņ†ŅŒ</string>
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<string name="revanced_hide_keyword_content_phrases_summary">"КĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ ҁĐģĐžĐ˛Ņ‹ Ņ– Ņ„Ņ€Đ°ĐˇŅ‹ Đ´ĐģŅ ŅŅ…Đ°Đ˛Đ°ĐŊĐŊŅ, ĐŋадСĐĩĐģĐĩĐŊŅ‹Ņ ĐŋĐĩŅ€Đ°Ņ…ĐžĐ´Đ°ĐŧŅ– ĐŊа ĐŊĐžĐ˛ŅƒŅŽ Ņ€Đ°Đ´ĐžĐē
@@ -377,7 +332,7 @@ Second \"item\" text"</string>
â€ĸ НĐĩĐēĐ°Ņ‚ĐžŅ€Ņ‹Ņ ŅĐģĐĩĐŧĐĩĐŊ҂ҋ Ņ–ĐŊŅ‚ŅŅ€Ņ„ĐĩĐšŅŅƒ ĐŧĐžĐŗŅƒŅ†ŅŒ ĐŊĐĩ ĐąŅ‹Ņ†ŅŒ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹
â€ĸ ĐŸĐžŅˆŅƒĐē Đŋа ĐēĐģŅŽŅ‡Đ°Đ˛Ņ‹Đŧ ҁĐģОвĐĩ ĐŧĐžĐļа ĐŊĐĩ ĐŋаĐēĐ°ĐˇĐ°Ņ†ŅŒ Đ˛Ņ‹ĐŊŅ–ĐēŅ–"</string>
<string name="revanced_hide_keyword_content_about_whole_words_title">ĐĄŅƒĐŋадСĐĩĐŊĐŊĐĩ Ņ†ŅĐģҋ҅ ҁĐģĐžŅž</string>
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<string name="revanced_hide_keyword_content_about_whole_words_summary">КаĐģŅ– Đ˛Ņ‹ Đ°Ņ…Ņ–ĐŊĐĩ҆Đĩ ĐēĐģŅŽŅ‡Đ°Đ˛ĐžĐĩ ҁĐģОва айО Ņ„Ņ€Đ°ĐˇŅƒ Ņž Đ´Đ˛ŅƒŅ…Ņ€Đ°ĐˇĐžĐ˛Ņ‹Ņ ĐģаĐŋĐēŅ–, ĐŗŅŅ‚Đ° ĐŋĐĩŅ€Đ°ŅˆĐēĐžĐ´ĐˇŅ–Ņ†ŅŒ Ņ‡Đ°ŅŅ‚ĐēОваĐŧ҃ ҁ҃ĐŋадСĐĩĐŊĐŊŅŽ ĐŊĐ°ĐˇĐ˛Đ°Ņž Đ˛Ņ–Đ´ŅĐ° Ņ– ĐēаĐŊаĐģĐ°Ņž&lt;br&gt;&lt;br&gt;НаĐŋҀҋĐēĐģад,&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt; ŅŅ…Đ°Đ˛Đ°Đĩ Đ˛Ņ–Đ´ŅĐ°: &lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt;аĐģĐĩ ĐŊĐĩ ŅŅ…Đ°Đ˛Đ°Đĩ: &lt;b&gt;What does fair use mean?&lt;/b&gt;</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="revanced_hide_keyword_toast_invalid_common">НĐĩĐģŅŒĐŗĐ° Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Ņ†ŅŒ ĐēĐģŅŽŅ‡Đ°Đ˛ĐžĐĩ ҁĐģОва: %s</string>
@@ -404,7 +359,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_self_sponsor_ads_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ŅĐ°ĐŧŅ– ҁĐŋаĐŊŅĐ°Đ˛Đ°ĐŊŅ‹Ņ ĐēĐ°Ņ€Ņ‚Ņ‹</string>
<string name="revanced_hide_self_sponsor_ads_summary_on">ĐĄĐŋĐžĐŊŅĐ°Ņ€ŅĐēŅ–Ņ ĐēĐ°Ņ€Ņ‚ĐēŅ– ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹Ņ</string>
<string name="revanced_hide_self_sponsor_ads_summary_off">ПаĐēĐ°ĐˇĐ˛Đ°ŅŽŅ†Ņ†Đ° ŅžĐģĐ°ŅĐŊŅ‹Ņ ĐēĐ°Ņ€Ņ‚Ņ‹</string>
<string name="revanced_hide_products_banner_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ йаĐŊĐĩŅ€ Đ´ĐģŅ ĐŋŅ€Đ°ĐŗĐģŅĐ´Ņƒ ĐŋŅ€Đ°Đ´ŅƒĐēŅ‚Đ°Ņž</string>
<string name="revanced_hide_products_banner_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ йаĐŊĐĩŅ€ ÂĢĐŸĐ°ĐŗĐģŅĐ´ĐˇĐĩŅ†ŅŒ ĐŋŅ€Đ°Đ´ŅƒĐē҂ҋÂģ</string>
<string name="revanced_hide_products_banner_summary_on">БаĐŊŅŅ€ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_hide_products_banner_summary_off">ПаĐēаСваĐĩŅ†Ņ†Đ° йаĐŊŅŅ€</string>
<string name="revanced_hide_end_screen_store_banner_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ йаĐŊĐĩŅ€ ĐēŅ€Đ°ĐŧŅ‹ ĐŊа ĐēаĐŊŅ‡Đ°Ņ‚ĐēĐžĐ˛Ņ‹Đŧ ŅĐēŅ€Đ°ĐŊĐĩ</string>
@@ -475,9 +430,9 @@ Second \"item\" text"</string>
<string name="revanced_disable_precise_seeking_gesture_summary_off">Đ–ŅŅŅ‚ ҃ĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
</patch>
<patch id="interaction.seekbar.enableSeekbarTappingPatch">
<string name="revanced_seekbar_tapping_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŊĐ°Ņ†Ņ–ŅĐē ĐŊа ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃</string>
<string name="revanced_seekbar_tapping_summary_on">ĐĐ°Ņ†Ņ–ŅĐē ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃ ŅžĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_seekbar_tapping_summary_off">ĐĐ°Ņ†Ņ–ŅĐē ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃ адĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
<string name="revanced_seekbar_tapping_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŊĐ°Ņ†Ņ–ŅĐēаĐŊĐŊĐĩ Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃</string>
<string name="revanced_seekbar_tapping_summary_on">ĐĐ°Ņ†Ņ–ŅĐŊҖ҆Đĩ, Đēай ҃ĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŋĐžŅˆŅƒĐē</string>
<string name="revanced_seekbar_tapping_summary_off">ĐĐ°Ņ†Ņ–ŅĐēаĐŊĐŊĐĩ Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃ адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
</patch>
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
<string name="revanced_swipe_brightness_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐļŅŅŅ‚ ŅŅ€ĐēĐ°ŅŅ†Ņ–</string>
@@ -490,9 +445,9 @@ Second \"item\" text"</string>
Đ ŅĐŗŅƒĐģŅŽĐšŅ†Đĩ ĐŗŅƒŅ‡ĐŊĐ°ŅŅ†ŅŒ, ĐŋŅ€Đ°Đ˛ĐžĐ´ĐˇŅŅ‡Ņ‹ ĐŋаĐģŅŒŅ†Đ°Đŧ вĐĩҀ҂ҋĐēаĐģҌĐŊа Đŋа ĐŋŅ€Đ°Đ˛Đ°Đš Ņ‡Đ°ŅŅ‚Ņ†Ņ‹ ŅĐēŅ€Đ°ĐŊа"</string>
<string name="revanced_swipe_volume_summary_off">ĐŸŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊĐĩ ĐŋаĐģŅŒŅ†Đ°Đŧ Đ´ĐģŅ Ņ€ŅĐŗŅƒĐģŅĐ˛Đ°ĐŊĐŊŅ ĐŗŅƒŅ‡ĐŊĐ°ŅŅ†Ņ– ва ŅžĐ˛ĐĩҁҌ ŅĐēŅ€Đ°ĐŊ Đ˛Ņ‹ĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_swipe_press_to_engage_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐļŅŅŅ‚ \"ĐŊĐ°Ņ†Ņ–ŅĐēаĐŊĐŊĐĩ Đ´ĐģŅ ĐŋŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊŅ ĐŋаĐģŅŒŅ†Đ°Đŧ\"</string>
<string name="revanced_swipe_press_to_engage_summary_on">ĐŸŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊĐĩ ĐŋаĐģŅŒŅ†Đ°Đŧ ҃ĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_swipe_press_to_engage_summary_off">ĐŸŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊĐĩ ĐŋаĐģŅŒŅ†Đ°Đŧ адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_swipe_press_to_engage_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐļŅŅŅ‚ ĐŋŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊŅ ĐŊĐ°Ņ†Ņ–ŅĐēаĐŧ</string>
<string name="revanced_swipe_press_to_engage_summary_on">ĐŸŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊĐĩ ĐŊĐ°Ņ†Ņ–ŅĐēаĐŧ ҃ĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_swipe_press_to_engage_summary_off">ĐŸŅ€Đ°Đ˛ŅĐ´ĐˇĐĩĐŊĐŊĐĩ ĐŊĐ°Ņ†Ņ–ŅĐēаĐŧ адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_swipe_haptic_feedback_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ Ņ‚Đ°Đē҂ҋĐģҌĐŊŅƒŅŽ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊŅƒŅŽ ŅŅƒĐ˛ŅĐˇŅŒ</string>
<string name="revanced_swipe_haptic_feedback_summary_on">ĐĸаĐē҂ҋĐģҌĐŊĐ°Ņ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊĐ°Ņ ŅŅƒĐ˛ŅĐˇŅŒ ҃ĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_swipe_haptic_feedback_summary_off">ĐĸаĐē҂ҋĐģҌĐŊĐ°Ņ ĐˇĐ˛Đ°Ņ€ĐžŅ‚ĐŊĐ°Ņ ŅŅƒĐ˛ŅĐˇŅŒ адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
@@ -663,7 +618,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_player_flyout_video_quality_footer_summary_off">ПаĐēаСваĐĩŅ†Ņ†Đ° ĐŊŅ–ĐļĐŊŅ– ĐēаĐģĐžĐŊŅ‚Ņ‹Ņ‚ŅƒĐģ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°</string>
</patch>
<patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch">
<string name="revanced_hide_player_previous_next_buttons_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐŋаĐŋŅŅ€ŅĐ´ĐŊŅ– &amp; ĐēĐŊĐžĐŋĐēŅ– ĐŊĐ°ŅŅ‚ŅƒĐŋĐŊĐ°ĐŗĐ° Đ˛Ņ–Đ´ŅĐ°</string>
<string name="revanced_hide_player_previous_next_buttons_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐŋаĐŋŅŅ€ŅĐ´ĐŊŅ–Ņ &amp; ĐēĐŊĐžĐŋĐēŅ– ÂĢДаĐģĐĩĐšÂģ</string>
<string name="revanced_hide_player_previous_next_buttons_summary_on">КĐŊĐžĐŋĐēŅ– ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹Ņ</string>
<string name="revanced_hide_player_previous_next_buttons_summary_off">ПаĐēĐ°ĐˇĐ˛Đ°ŅŽŅ†Ņ†Đ° ĐēĐŊĐžĐŋĐēŅ–</string>
<string name="revanced_hide_cast_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐŊĐžĐŋĐē҃ ÂĢĐĸŅ€Đ°ĐŊҁĐģŅŅ†Ņ‹ŅÂģ</string>
@@ -856,7 +811,6 @@ Second \"item\" text"</string>
<string name="revanced_ryd_enable_summary_on">Đ”Ņ‹ĐˇĐģаКĐēŅ– ĐŋаĐēаСаĐŊŅ‹</string>
<string name="revanced_ryd_enable_summary_off">Đ”Ņ‹ĐˇĐģаКĐēŅ– ĐŊĐĩ ĐŋаĐēĐ°ĐˇĐ˛Đ°ŅŽŅ†Ņ†Đ°</string>
<string name="revanced_ryd_shorts_title">ПаĐēĐ°ĐˇĐ˛Đ°ĐšŅ†Đĩ \"ĐŊĐĩ ĐŋадайаĐĩŅ†Ņ†Đ°\" ĐŊа Shorts</string>
<string name="revanced_ryd_shorts_summary_on">Đ”Ņ‹ĐˇĐģаКĐēŅ– ĐŊа Shorts ĐŋаĐēаСаĐŊŅ‹Ņ</string>
<string name="revanced_ryd_shorts_summary_on_disclaimer">"Đ”Ņ‹ĐˇĐģаКĐēŅ– ĐŊа Shorts ĐŋаĐēаСаĐŊŅ‹Ņ
АйĐŧĐĩĐļаваĐŊĐŊĐĩ: Đ´Ņ‹ĐˇĐģаКĐēŅ– ĐŧĐžĐŗŅƒŅ†ŅŒ ĐŊĐĩ адĐģŅŽŅŅ‚Ņ€ĐžŅžĐ˛Đ°Ņ†Ņ†Đ° Ņž Ņ€ŅĐļŅ‹ĐŧĐĩ Ņ–ĐŊĐēĐžĐŗĐŊŅ–Ņ‚Đ°"</string>
@@ -1055,6 +1009,8 @@ Second \"item\" text"</string>
<string name="revanced_sb_vote_downvote">ГаĐģĐ°ŅĐ°Đ˛Đ°Ņ†ŅŒ ҁ҃ĐŋŅ€Đ°Ņ†ŅŒ</string>
<string name="revanced_sb_vote_category">ЗĐŧŅĐŊŅ–Ņ†ŅŒ ĐēĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹ŅŽ</string>
<string name="revanced_sb_vote_no_segments">ĐŅĐŧа ҁĐĩĐŗĐŧĐĩĐŊŅ‚Đ°Ņž Đ´ĐģŅ ĐŗĐ°ĐģĐ°ŅĐ°Đ˛Đ°ĐŊĐŊŅ</string>
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<string name="revanced_sb_vote_segment_time_to_from">%1$s да %2$s</string>
<string name="revanced_sb_new_segment_choose_category">Đ’Ņ‹ĐąĐĩҀҋ҆Đĩ ĐēĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹ŅŽ ҁĐĩĐŗĐŧĐĩĐŊŅ‚Đ°</string>
<string name="revanced_sb_new_segment_disabled_category">ĐšĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹Ņ адĐēĐģŅŽŅ‡Đ°ĐŊа Ņž ĐŊаĐģĐ°Đ´Đ°Ņ…. ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†Đĩ ĐēĐ°Ņ‚ŅĐŗĐžŅ€Ņ‹ŅŽ Đ´ĐģŅ адĐŋŅ€Đ°ŅžĐēŅ–.</string>
<string name="revanced_sb_new_segment_title">ĐĐžĐ˛Ņ‹ ҁĐĩĐŗĐŧĐĩĐŊŅ‚ SponsorBlock</string>
@@ -1102,6 +1058,7 @@ Second \"item\" text"</string>
<string name="revanced_sb_stats_saved_hour_format">%1$s ĐŗĐ°Đ´ĐˇŅ–ĐŊ %2$s Ņ…Đ˛Ņ–ĐģŅ–ĐŊ</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s Ņ…Đ˛Ņ–ĐģŅ–ĐŊ %2$s ҁĐĩĐē҃ĐŊĐ´</string>
<string name="revanced_sb_stats_saved_second_format">%s ҁĐĩĐē҃ĐŊĐ´</string>
<string name="revanced_sb_color_opacity_label">НĐĩĐŋŅ€Đ°ĐˇŅ€Ņ‹ŅŅ‚Đ°ŅŅ†ŅŒ:</string>
<string name="revanced_sb_color_dot_label">ĐēĐžĐģĐĩŅ€:</string>
<string name="revanced_sb_color_changed">КоĐģĐĩŅ€ СĐŧŅĐŊŅ–ŅžŅŅ</string>
<string name="revanced_sb_color_reset">ĐĄĐēŅ–Đ´ ĐēĐžĐģĐĩŅ€Ņƒ</string>
@@ -1119,13 +1076,11 @@ Second \"item\" text"</string>
<string name="revanced_change_form_factor_entry_4">ĐŅžŅ‚Đ°ĐŧĐ°ĐąŅ–ĐģҌĐŊŅ‹</string>
<string name="revanced_change_form_factor_user_dialog_message">"ЗĐŧĐĩĐŊŅ‹ ŅžĐēĐģŅŽŅ‡Đ°ŅŽŅ†ŅŒ:
Đ Đ°ŅĐēĐģадĐēа ĐŋĐģаĐŊŅˆŅŅ‚Đ°
â€ĸ ПавĐĩдаĐŧĐģĐĩĐŊĐŊŅ– ҁ҃ĐŋĐžĐģҌĐŊĐ°ŅŅ†Ņ– ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹
МаĐēĐĩŅ‚ Đ´ĐģŅ ĐŋĐģаĐŊŅˆŅŅ‚Đ°
â€ĸ ПавĐĩдаĐŧĐģĐĩĐŊĐŊŅ– ҁ҃ĐŋĐžĐģҌĐŊĐ°ŅŅ†Ņ– ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹Ņ
Đ Đ°ŅĐēĐģадĐēа Đ°ŅžŅ‚Đ°ĐŧĐ°ĐąŅ–ĐģŅ
â€ĸ МĐĩĐŊŅŽ ĐŗŅ–ŅŅ‚ĐžŅ€Ņ‹Ņ– ĐŋŅ€Đ°ĐŗĐģŅĐ´Đ°Ņž ŅŅ…Đ°Đ˛Đ°ĐŊа
â€ĸ АдĐŊĐžŅžĐģĐĩĐŊа ŅžĐēĐģадĐēа ÂĢĐ”Đ°ŅĐģĐĩĐ´Đ°Đ˛Đ°Ņ†ŅŒÂģ
â€ĸ Đ ĐžĐģŅ–ĐēŅ– Shorts адĐēŅ€Ņ‹Đ˛Đ°ŅŽŅ†Ņ†Đ° Ņž ĐˇĐ˛Ņ‹Ņ‡Đ°ĐšĐŊŅ‹Đŧ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐģҌĐŊŅ–Đē҃
ĐŅžŅ‚Đ°ĐŧĐ°ĐąŅ–ĐģҌĐŊŅ‹ ĐŧаĐēĐĩŅ‚
â€ĸ Shorts адĐēŅ€Ņ‹Đ˛Đ°ŅŽŅ†Ņ†Đ° Ņž ĐˇĐ˛Ņ‹Ņ‡Đ°ĐšĐŊŅ‹Đŧ ĐŋĐģŅĐĩҀҋ
â€ĸ ĐĄŅ‚ŅƒĐļĐēа Đ°Ņ€ĐŗĐ°ĐŊŅ–ĐˇĐ°Đ˛Đ°ĐŊа Đŋа Ņ‚ŅĐŧĐ°Ņ… Ņ– ĐēаĐŊаĐģĐ°Ņ…"</string>
</patch>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
@@ -1141,12 +1096,7 @@ Second \"item\" text"</string>
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<string name="revanced_spoof_app_version_target_title">ĐŸĐ°Đ´Ņ€ĐžĐąĐēа ĐŧŅŅ‚Đ°Đ˛Đ°Đš вĐĩҀҁҖҖ ĐŋŅ€Đ°ĐŗŅ€Đ°ĐŧŅ‹</string>
<string name="revanced_spoof_app_version_target_entry_1">19.35.36 — Đ’ĐžŅŅŅ‚Đ°ĐŊĐžĐ˛Đ¸Ņ‚ŅŒ ŅŅ‚Đ°Ņ€Ņ‹Đĩ СĐŊĐ°Ņ‡Đēи ĐŋĐģĐĩĐĩŅ€Đ° Shorts</string>
<string name="revanced_spoof_app_version_target_entry_2">19.26.42 - АдĐŊĐ°ŅžĐģĐĩĐŊĐŊĐĩ ŅŅ‚Đ°Ņ€Ņ‹Ņ… СĐŊĐ°Ņ‡ĐēĐžŅž ĐŊĐ°Đ˛Ņ–ĐŗĐ°Ņ†Ņ‹Ņ–</string>
<!-- 'RYD' is 'Return YouTube Dislike' -->
<string name="revanced_spoof_app_version_target_legacy_entry_1">18.33.40 - АдĐŊĐ°ŅžĐģĐĩĐŊĐŊĐĩ RYD ĐŊа Shorts ҃ Ņ€ŅĐļŅ‹ĐŧĐĩ Ņ–ĐŊĐēĐžĐŗĐŊŅ–Ņ‚Đ°</string>
<string name="revanced_spoof_app_version_target_legacy_entry_2">18.20.39 - АдĐŊĐ°Đ˛Ņ–Ņ†ŅŒ Ņ…ŅƒŅ‚ĐēĐ°ŅŅ†ŅŒ ŅˆŅ‹Ņ€ĐžĐēĐ°ĐŗĐ° Đ˛Ņ–Đ´ŅĐ° &amp; ŅĐēĐ°ŅĐŊаĐĩ ĐŧĐĩĐŊŅŽ</string>
<string name="revanced_spoof_app_version_target_legacy_entry_3">18.09.39 - АдĐŊĐ°ŅžĐģĐĩĐŊĐŊĐĩ ŅžĐēĐģадĐēŅ– ĐąŅ–ĐąĐģŅ–ŅŅ‚ŅĐēŅ–</string>
<string name="revanced_spoof_app_version_target_legacy_entry_4">17.33.42 - АдĐŊĐ°ŅžĐģĐĩĐŊĐŊĐĩ ŅŅ‚Đ°Ņ€ĐžĐš ĐŋаĐģҖ҆ҋ ĐŋĐģŅĐšĐģŅ–ŅŅ‚ĐžŅž</string>
<string name="revanced_spoof_app_version_target_entry_2">19.01.34 - АдĐŊĐ°ŅžĐģĐĩĐŊĐŊĐĩ ŅŅ‚Đ°Ņ€Ņ‹Ņ… СĐŊĐ°Ņ‡ĐēĐžŅž ĐŊĐ°Đ˛Ņ–ĐŗĐ°Ņ†Ņ‹Ņ–</string>
</patch>
<patch id="layout.startpage.changeStartPagePatch">
<string name="revanced_change_start_page_title">ĐŖŅŅ‚Đ°ĐģŅĐ˛Đ°Ņ†ŅŒ ŅŅ‚Đ°Ņ€Ņ‚Đ°Đ˛ŅƒŅŽ ŅŅ‚Đ°Ņ€ĐžĐŊĐē҃</string>
@@ -1196,7 +1146,7 @@ Second \"item\" text"</string>
</patch>
<patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">ĐœŅ–ĐŊŅ–-ĐŋĐģŅĐĩŅ€</string>
<string name="revanced_miniplayer_screen_summary">ЗĐŧŅĐŊҖ҆Đĩ ҁ҂ҋĐģҌ ĐŧŅ–ĐŊŅ–ĐŧŅ–ĐˇĐ°Đ˛Đ°ĐŊĐ°ĐŗĐ° ĐŋĐģŅĐĩŅ€Đ° Ņž ĐŋŅ€Đ°ĐŗŅ€Đ°ĐŧĐĩ</string>
<string name="revanced_miniplayer_screen_summary">ЗĐŧŅĐŊŅ–Ņ†ŅŒ ҁ҂ҋĐģҌ ĐˇĐŗĐžŅ€ĐŊŅƒŅ‚Đ°ĐŗĐ° ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐģҌĐŊŅ–Đēа Ņž ĐŋŅ€Đ°ĐŗŅ€Đ°ĐŧĐĩ</string>
<string name="revanced_miniplayer_type_title">ĐĸŅ‹Đŋ ĐŧŅ–ĐŊŅ–ĐŋĐģŅĐĩŅ€Đ°</string>
<string name="revanced_miniplayer_type_entry_0">ІĐŊваĐģŅ–Đ´Ņ‹</string>
<string name="revanced_miniplayer_type_entry_1">Па СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ–</string>
@@ -1249,8 +1199,6 @@ Second \"item\" text"</string>
<string name="revanced_gradient_loading_screen_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ĐŗŅ€Đ°Đ´Ņ‹ĐĩĐŊŅ‚ĐŊŅ‹ ŅĐēŅ€Đ°ĐŊ ĐˇĐ°ĐŗŅ€ŅƒĐˇĐēŅ–</string>
<string name="revanced_gradient_loading_screen_summary_on">Đ­ĐēŅ€Đ°ĐŊ ĐˇĐ°ĐŗŅ€ŅƒĐˇĐēŅ– ĐąŅƒĐ´ĐˇĐĩ ĐŧĐĩŅ†ŅŒ ĐŗŅ€Đ°Đ´Ņ‹ĐĩĐŊŅ‚ĐŊŅ‹ Ņ„ĐžĐŊ</string>
<string name="revanced_gradient_loading_screen_summary_off">Đ­ĐēŅ€Đ°ĐŊ ĐˇĐ°ĐŗŅ€ŅƒĐˇĐēŅ– ĐąŅƒĐ´ĐˇĐĩ ĐŧĐĩŅ†ŅŒ ŅŅƒŅ†ŅĐģҌĐŊŅ‹ Ņ„ĐžĐŊ</string>
</patch>
<patch id="layout.theme.themeResourcePatch">
<string name="revanced_seekbar_custom_color_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ҃ĐģĐ°ŅĐŊŅ‹ ĐēĐžĐģĐĩŅ€ ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃</string>
<string name="revanced_seekbar_custom_color_summary_on">ПаĐēаСваĐĩŅ†Ņ†Đ° ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐģҌĐŊҖ҆ĐēŅ– ĐēĐžĐģĐĩŅ€ ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃</string>
<string name="revanced_seekbar_custom_color_summary_off">ПаĐēаСаĐŊŅ‹ ĐˇŅ‹Ņ…ĐžĐ´ĐŊŅ‹ ĐēĐžĐģĐĩŅ€ ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃</string>
@@ -1342,8 +1290,8 @@ Second \"item\" text"</string>
</patch>
<patch id="misc.links.openLinksExternallyPatch">
<string name="revanced_external_browser_title">АдĐēŅ€Ņ‹Đ˛Đ°Ņ†ŅŒ ҁĐŋĐ°ŅŅ‹ĐģĐēŅ– Ņž ĐąŅ€Đ°ŅžĐˇĐĩҀҋ</string>
<string name="revanced_external_browser_summary_on">АдĐēҀҋ҆҆ґ ҁĐŋĐ°ŅŅ‹ĐģаĐē СвОĐŊĐē҃</string>
<string name="revanced_external_browser_summary_off">АдĐēҀҋ҆҆ґ ҁĐŋĐ°ŅŅ‹ĐģаĐē ҃ ĐŋŅ€Đ°ĐŗŅ€Đ°ĐŧĐĩ</string>
<string name="revanced_external_browser_summary_on">АдĐēҀҋ҆҆ґ ҁĐŋĐ°ŅŅ‹ĐģаĐē ҃ СĐŊĐĩ҈ĐŊŅ–Đŧ ĐąŅ€Đ°ŅžĐˇĐĩҀҋ</string>
<string name="revanced_external_browser_summary_off">АдĐēҀҋ҆҆ґ ҁĐŋĐ°ŅŅ‹ĐģаĐē ва ŅžĐąŅƒĐ´Đ°Đ˛Đ°ĐŊŅ‹Đŧ ĐąŅ€Đ°ŅžĐˇĐĩҀҋ</string>
</patch>
<patch id="misc.privacy.removeTrackingQueryParameterPatch">
<string name="revanced_remove_tracking_query_parameter_title">Đ’Ņ‹Đ´Đ°ĐģŅ–Ņ†ŅŒ ĐŋĐ°Ņ€Đ°ĐŧĐĩ҂Ҁ СаĐŋŅ‹Ņ‚Ņƒ Đ°Đ´ŅĐžŅ‡Đ˛Đ°ĐŊĐŊŅ</string>
@@ -1370,9 +1318,15 @@ Second \"item\" text"</string>
<string name="revanced_remember_video_quality_last_selected_summary_off">ЗĐŧĐĩĐŊŅ‹ ŅĐēĐ°ŅŅ†Ņ– ĐŋҀҋĐŧŅĐŊŅŅŽŅ†Ņ†Đ° Ņ‚ĐžĐģҌĐēŅ– да ĐąŅĐŗŅƒŅ‡Đ°ĐŗĐ° Đ˛Ņ–Đ´ŅĐ°</string>
<string name="revanced_video_quality_default_wifi_title">ĐĄŅ‚Đ°ĐŊĐ´Đ°Ņ€Ņ‚ĐŊĐ°Ņ ŅĐēĐ°ŅŅ†ŅŒ Đ˛Ņ–Đ´ŅĐ° Ņž ҁĐĩ҂҆ҋ Wi-Fi</string>
<string name="revanced_video_quality_default_mobile_title">ĐĄŅ‚Đ°ĐŊĐ´Đ°Ņ€Ņ‚ĐŊĐ°Ņ ŅĐēĐ°ŅŅ†ŅŒ Đ˛Ņ–Đ´ŅĐ° Ņž ĐŧĐ°ĐąŅ–ĐģҌĐŊаК ҁĐĩ҂҆ҋ</string>
<string name="revanced_remember_shorts_quality_last_selected_title">ЗаĐŋĐžĐŧĐŊŅ–Ņ†ŅŒ СĐŧĐĩĐŊŅ‹ ŅĐēĐ°ŅŅ†Ņ– Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">ЗĐŧĐĩĐŊŅ‹ ŅĐēĐ°ŅŅ†Ņ– ĐŋҀҋĐŧŅĐŊŅŅŽŅ†Ņ†Đ° да ŅžŅŅ–Ņ… Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">ЗĐŧĐĩĐŊŅ‹ ŅĐēĐ°ŅŅ†Ņ– ĐŋҀҋĐŧŅĐŊŅŅŽŅ†Ņ†Đ° Ņ‚ĐžĐģҌĐēŅ– да ĐąŅĐŗŅƒŅ‡Đ°ĐŗĐ° Short</string>
<string name="revanced_shorts_quality_default_wifi_title">Đ¯ĐēĐ°ŅŅ†ŅŒ Shorts Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ– Ņž ҁĐĩ҂҆ҋ Wi-Fi</string>
<string name="revanced_shorts_quality_default_mobile_title">Đ¯ĐēĐ°ŅŅ†ŅŒ Shorts Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ– Ņž ĐŧĐ°ĐąŅ–ĐģҌĐŊаК ҁĐĩ҂҆ҋ</string>
<string name="revanced_remember_video_quality_mobile">ĐŧĐ°ĐąŅ–ĐģҌĐŊŅ‹</string>
<string name="revanced_remember_video_quality_wifi">wi-fi</string>
<string name="revanced_remember_video_quality_toast">ĐĄŅ‚Đ°ĐŊĐ´Đ°Ņ€Ņ‚ĐŊĐ°Ņ ŅĐēĐ°ŅŅ†ŅŒ %1$s СĐŧĐĩĐŊĐĩĐŊа ĐŊа: %2$s</string>
<string name="revanced_remember_video_quality_toast_shorts">Đ¯ĐēĐ°ŅŅ†ŅŒ Shorts %1$s СĐŧĐĩĐŊĐĩĐŊа ĐŊа: %2$s</string>
</patch>
<patch id="video.speed.button.playbackSpeedButtonPatch">
<string name="revanced_playback_speed_dialog_button_title">ПаĐēĐ°ĐˇĐ°Ņ†ŅŒ Đ´Ņ‹ŅĐģĐžĐŗĐ°Đ˛ŅƒŅŽ ĐēĐŊĐžĐŋĐē҃ Ņ…ŅƒŅ‚ĐēĐ°ŅŅ†Ņ–</string>
@@ -1403,10 +1357,10 @@ Second \"item\" text"</string>
<string name="revanced_disable_hdr_video_summary_on">Đ’Ņ–Đ´ŅĐ° Ņž Ņ„Đ°Ņ€ĐŧĐ°Ņ†Đĩ HDR адĐēĐģŅŽŅ‡Đ°ĐŊа</string>
<string name="revanced_disable_hdr_video_summary_off">Đ’Ņ–Đ´ŅĐ° Ņž Ņ„Đ°Ņ€ĐŧĐ°Ņ†Đĩ HDR ҃ĐēĐģŅŽŅ‡Đ°ĐŊа</string>
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<string name="revanced_restore_old_video_quality_menu_title">АдĐŊĐ°Đ˛Ņ–Ņ†ŅŒ ŅŅ‚Đ°Ņ€ĐžĐĩ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°</string>
<string name="revanced_restore_old_video_quality_menu_summary_on">ПаĐēаСаĐŊа ŅŅ‚Đ°Ņ€ĐžĐĩ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°</string>
<string name="revanced_restore_old_video_quality_menu_summary_off">ĐĄŅ‚Đ°Ņ€ĐžĐĩ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ° ĐŊĐĩ ĐŋаĐēаСваĐĩŅ†Ņ†Đ°</string>
<patch id="video.quality.advancedVideoQualityMenuPatch">
<string name="revanced_advanced_video_quality_menu_title">ПаĐēĐ°ĐˇĐ°Ņ†ŅŒ ĐŋĐ°ŅˆŅ‹Ņ€Đ°ĐŊаĐĩ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ°</string>
<string name="revanced_advanced_video_quality_menu_summary_on">ĐŸĐ°ŅˆŅ‹Ņ€Đ°ĐŊаĐĩ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ° ĐŋаĐēаСаĐŊа</string>
<string name="revanced_advanced_video_quality_menu_summary_off">ĐŸĐ°ŅˆŅ‹Ņ€Đ°ĐŊаĐĩ ĐŧĐĩĐŊŅŽ ŅĐēĐ°ŅŅ†Ņ– Đ˛Ņ–Đ´ŅĐ° ĐŊĐĩ ĐŋаĐēаСаĐŊа</string>
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
<string name="revanced_slide_to_seek_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ ҁĐģаКд Đ´ĐģŅ ĐŋĐžŅˆŅƒĐē҃</string>

View File

@@ -48,57 +48,6 @@ Second \"item\" text"</string>
За да ĐŋŅ€ĐĩвĐĩĐ´ĐĩŅ‚Đĩ ĐŊОви ĐĩĐˇĐ¸Ņ†Đ¸, ĐŋĐžŅĐĩŅ‚ĐĩŅ‚Đĩ translate.revanced.app"</string>
<string name="revanced_language_DEFAULT">ЕзиĐē ĐŊа ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩŅ‚Đž</string>
<string name="revanced_language_AR">Đ°Ņ€Đ°ĐąŅĐēи</string>
<string name="revanced_language_AZ">АСĐĩŅ€ĐąĐ°ĐšĐ´ĐļаĐŊҁĐēи</string>
<string name="revanced_language_BG">ĐąŅŠĐģĐŗĐ°Ņ€ŅĐēи</string>
<string name="revanced_language_BN">ĐąĐĩĐŊĐŗĐ°ĐģҁĐēи</string>
<string name="revanced_language_CA">ĐēĐ°Ņ‚Đ°ĐģĐžĐŊҁĐēи</string>
<string name="revanced_language_CS">ЧĐĩ҈Đēи</string>
<string name="revanced_language_DA">Đ”Đ°Ņ‚ŅĐēи</string>
<string name="revanced_language_DE">НĐĩĐŧҁĐēи</string>
<string name="revanced_language_EL">Đ“Ņ€ŅŠŅ†Đēи</string>
<string name="revanced_language_EN">АĐŊĐŗĐģĐ¸ĐšŅĐēи</string>
<string name="revanced_language_ES">Đ˜ŅĐŋаĐŊҁĐēи</string>
<string name="revanced_language_ET">Đ•ŅŅ‚ĐžĐŊҁĐēи</string>
<string name="revanced_language_FA">ПĐĩŅ€ŅĐ¸ĐšŅĐēи</string>
<string name="revanced_language_FI">ФиĐŊĐģаĐŊĐ´ŅĐēи</string>
<string name="revanced_language_FR">Đ¤Ņ€ĐĩĐŊҁĐēи</string>
<string name="revanced_language_GU">Đ“ŅƒĐ´ĐļĐ°Ņ€Đ°Ņ‚Đ¸</string>
<string name="revanced_language_HI">ĐĨиĐŊди</string>
<string name="revanced_language_HR">ĐĨŅŠŅ€Đ˛Đ°Ņ‚ŅĐēи</string>
<string name="revanced_language_HU">ĐŖĐŊĐŗĐ°Ņ€ŅĐēи</string>
<string name="revanced_language_ID">ИĐŊĐ´ĐžĐŊĐĩĐˇĐ¸ĐšŅĐēи</string>
<string name="revanced_language_IT">Đ˜Ņ‚Đ°ĐģиаĐŊҁĐēи</string>
<string name="revanced_language_JA">Đ¯ĐŋĐžĐŊҁĐēи</string>
<string name="revanced_language_KK">ĐšĐ°ĐˇĐ°Ņ…ŅĐēи</string>
<string name="revanced_language_KO">ĐšĐžŅ€ĐĩĐšŅĐēи</string>
<string name="revanced_language_LT">Đ›Đ¸Ņ‚ĐžĐ˛ŅĐēи</string>
<string name="revanced_language_LV">Đ›Đ°Ņ‚Đ˛Đ¸ĐšŅĐēи</string>
<string name="revanced_language_MK">МаĐēĐĩĐ´ĐžĐŊҁĐēи</string>
<string name="revanced_language_MN">МоĐŊĐŗĐžĐģҁĐēи</string>
<string name="revanced_language_MR">ĐœĐ°Ņ€Đ°Ņ‚Ņ…Đ¸</string>
<string name="revanced_language_MS">МаĐģĐ°ĐšŅĐēи</string>
<string name="revanced_language_MY">Đ‘Đ¸Ņ€ĐŧаĐŊҁĐēи</string>
<string name="revanced_language_NL">ĐĨĐžĐģаĐŊĐ´ŅĐēи</string>
<string name="revanced_language_OR">ĐžĐ´Đ¸Ņ</string>
<string name="revanced_language_PA">ПĐĩĐŊĐ´Đļайи</string>
<string name="revanced_language_PL">ПоĐģҁĐēи</string>
<string name="revanced_language_PT">ĐŸĐžŅ€Ņ‚ŅƒĐŗĐ°ĐģҁĐēи</string>
<string name="revanced_language_RO">Đ ŅƒĐŧҊĐŊҁĐēи</string>
<string name="revanced_language_RU">Đ ŅƒŅĐēи</string>
<string name="revanced_language_SK">ĐĄĐģĐžĐ˛Đ°ŅˆĐēи</string>
<string name="revanced_language_SL">ĐĄĐģОвĐĩĐŊҁĐēи</string>
<string name="revanced_language_SR">ĐĄŅ€ŅŠĐąŅĐēи</string>
<string name="revanced_language_SV">ШвĐĩĐ´ŅĐēи</string>
<string name="revanced_language_SW">ĐĄŅƒĐ°Ņ…Đ¸Đģи</string>
<string name="revanced_language_TA">ĐĸаĐŧиĐģҁĐēи</string>
<string name="revanced_language_TE">ĐĸĐĩĐģŅƒĐŗŅƒ</string>
<string name="revanced_language_TH">ĐĸаКĐģаĐŊĐ´ŅĐēи</string>
<string name="revanced_language_TR">ĐĸŅƒŅ€ŅĐēи</string>
<string name="revanced_language_UK">ĐŖĐēŅ€Đ°Đ¸ĐŊҁĐēи</string>
<string name="revanced_language_UR">ĐŖŅ€Đ´Ņƒ</string>
<string name="revanced_language_VI">ВиĐĩŅ‚ĐŊаĐŧҁĐēи</string>
<string name="revanced_language_ZH">ĐšĐ¸Ņ‚Đ°ĐšŅĐēи</string>
<string name="revanced_pref_import_export_title">ИĐŧĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ / ЕĐēҁĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ</string>
<string name="revanced_pref_import_export_summary">ИĐŧĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ / ЕĐēҁĐŋĐžŅ€Ņ‚Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ReVanced ĐŊĐ°ŅŅ‚Ņ€ĐžĐšĐēĐ¸Ņ‚Đĩ</string>
<!-- Settings about dialog. -->
@@ -277,6 +226,9 @@ Second \"item\" text"</string>
<string name="revanced_hide_artist_cards_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ĐēĐ°Ņ€Ņ‚Đ¸Ņ‚Đĩ ĐŊа Đ°Ņ€Ņ‚Đ¸ŅŅ‚Đ¸Ņ‚Đĩ</string>
<string name="revanced_hide_artist_cards_summary_on">ĐšĐ°Ņ€Ņ‚Đ¸Ņ‚Đĩ ĐŊа иСĐŋҊĐģĐŊĐ¸Ņ‚ĐĩĐģĐ¸Ņ‚Đĩ ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸</string>
<string name="revanced_hide_artist_cards_summary_off">ПоĐēĐ°ĐˇĐ˛Đ°Ņ‚ ҁĐĩ ĐēĐ°Ņ€Ņ‚Đ¸ ĐŊа Đ°Ņ€Ņ‚Đ¸ŅŅ‚Đ¸</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа \"AI-ĐŗĐĩĐŊĐĩŅ€Đ¸Ņ€Đ°ĐŊĐž видĐĩĐž Ņ€ĐĩĐˇŅŽĐŧĐĩ\"</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">ĐĄĐēŅ€Đ¸Ņ‚ Đĩ Ņ€Đ°ĐˇĐ´ĐĩĐģŅŠŅ‚ ҁ видĐĩĐž Ņ€ĐĩĐˇŅŽĐŧĐĩ</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">ПоĐēаСва ҁĐĩ Ņ€Đ°ĐˇĐ´ĐĩĐģŅŠŅ‚ ҁ видĐĩĐž Ņ€ĐĩĐˇŅŽĐŧĐĩ</string>
<string name="revanced_hide_attributes_section_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа Đ°Ņ‚Ņ€Đ¸ĐąŅƒŅ‚Đ¸</string>
<string name="revanced_hide_attributes_section_summary_on">ĐĄĐĩĐēŅ†Đ¸Đ¸Ņ‚Đĩ \"ĐŸŅ€ĐĩĐŋĐžŅ€ŅŠŅ‡Đ°ĐŊи ĐŧĐĩŅŅ‚Đ°\", \"Đ˜ĐŗŅ€Đ¸\", \"ĐœŅƒĐˇĐ¸Đēа\" и \"ĐĄĐŋĐžĐŧĐĩĐŊĐ°Ņ‚Đ¸ Ņ…ĐžŅ€Đ°\" ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸</string>
<string name="revanced_hide_attributes_section_summary_off">ĐĄĐĩĐēŅ†Đ¸Đ¸Ņ‚Đĩ \"ĐŸŅ€ĐĩĐŋĐžŅ€ŅŠŅ‡Đ°ĐŊи ĐŧĐĩŅŅ‚Đ°\", \"Đ˜ĐŗŅ€Đ¸\", \"ĐœŅƒĐˇĐ¸Đēа\" и \"ĐĄĐŋĐžĐŧĐĩĐŊĐ°Ņ‚Đ¸ Ņ…ĐžŅ€Đ°\" ŅĐ° ĐŋĐžĐēаСаĐŊи</string>
@@ -313,9 +265,12 @@ Second \"item\" text"</string>
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">ПоĐēаСаĐŊĐž в ŅŅ€ĐžĐ´ĐŊи видĐĩĐžĐēĐģиĐŋОвĐĩ</string>
<string name="revanced_comments_screen_title">КоĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸</string>
<string name="revanced_comments_screen_summary">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ иĐģи ĐŋĐžĐēаСваĐŊĐĩ ĐŊа ҁĐĩĐēŅ†Đ¸ŅŅ‚Đ° Са ĐēĐžĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸</string>
<string name="revanced_hide_comments_chat_summary_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа \"Đ ĐĩĐˇŅŽĐŧĐĩ ĐŊа Ņ‡Đ°Ņ‚Đ°\"</string>
<string name="revanced_hide_comments_chat_summary_summary_on">Đ ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа Ņ‡Đ°Ņ‚Đ° Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
<string name="revanced_hide_comments_chat_summary_summary_off">Đ ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа Ņ‡Đ°Ņ‚Đ° Đĩ ĐŋĐžĐēаСаĐŊĐž</string>
<string name="revanced_hide_comments_ai_chat_summary_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа Ņ€ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа AI Chat</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">Đ ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа Ņ‡Đ°Ņ‚Đ° Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">Đ ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа Ņ‡Đ°Ņ‚Đ° Đĩ ĐŋĐžĐēаСаĐŊĐž</string>
<string name="revanced_hide_comments_ai_summary_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа Ņ€ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа AI ĐēĐžĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ</string>
<string name="revanced_hide_comments_ai_summary_summary_on">Đ ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа ĐēĐžĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
<string name="revanced_hide_comments_ai_summary_summary_off">Đ ĐĩĐˇŅŽĐŧĐĩŅ‚Đž ĐŊа ĐēĐžĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ Đĩ ĐŋĐžĐēаСаĐŊĐž</string>
<string name="revanced_hide_comments_by_members_header_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа „КоĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸, ĐŊаĐŋŅ€Đ°Đ˛ĐĩĐŊи ĐžŅ‚ ҇ĐģĐĩĐŊОвĐĩ“</string>
<string name="revanced_hide_comments_by_members_header_summary_on">Đ—Đ°ĐŗĐģавиĐĩŅ‚Đž ĐŊа ĐēĐžĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ ĐžŅ‚ ҇ĐģĐĩĐŊОвĐĩ Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
<string name="revanced_hide_comments_by_members_header_summary_off">Đ—Đ°ĐŗĐģавиĐĩŅ‚Đž ĐŊа ĐēĐžĐŧĐĩĐŊŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ ĐžŅ‚ ҇ĐģĐĩĐŊОвĐĩ Đĩ ĐŋĐžĐēаСаĐŊĐž</string>
@@ -362,7 +317,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_on">ВидĐĩĐžĐēĐģиĐŋОвĐĩŅ‚Đĩ в Ņ€Đ°ĐˇĐ´ĐĩĐģа Са айОĐŊаĐŧĐĩĐŊŅ‚Đ¸ ŅĐ° ŅĐ° Ņ„Đ¸ĐģŅ‚Ņ€Đ¸Ņ€Đ°ĐŊи ҁ ĐēĐģŅŽŅ‡ĐžĐ˛Đ¸ Đ´ŅƒĐŧи</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_off">ВидĐĩĐžĐēĐģиĐŋОвĐĩŅ‚Đĩ в ĐĩĐŧĐ¸ŅĐ¸ŅŅ‚Đ° Са айОĐŊаĐŧĐĩĐŊŅ‚Đ¸ ĐŊĐĩ ҁĐĩ Ņ„Đ¸ĐģŅ‚Ņ€Đ¸Ņ€Đ°Ņ‚</string>
<string name="revanced_hide_keyword_content_phrases_title">КĐģŅŽŅ‡ĐžĐ˛Đ¸ Đ´ŅƒĐŧи, ĐēĐžĐ¸Ņ‚Đž да ĐąŅŠĐ´Đ°Ņ‚ ҁĐēŅ€Đ¸Ņ‚Đ¸</string>
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<string name="revanced_hide_keyword_content_phrases_summary">"КĐģŅŽŅ‡ĐžĐ˛Đ¸ Đ´ŅƒĐŧи и Ņ„Ņ€Đ°ĐˇĐ¸ Са ҁĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ, Ņ€Đ°ĐˇĐ´ĐĩĐģĐĩĐŊи ĐžŅ‚ ĐŊОв Ņ€ĐĩĐ´
@@ -377,7 +332,7 @@ Second \"item\" text"</string>
â€ĸ ĐŅĐēОи UI ĐēĐžĐŧĐŋĐžĐŊĐĩĐŊŅ‚Đ¸ ĐŧĐžĐļĐĩ да ĐŊĐĩ ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸
â€ĸ ĐĸŅŠŅ€ŅĐĩĐŊĐĩŅ‚Đž ĐŊа ĐēĐģŅŽŅ‡ĐžĐ˛Đ° Đ´ŅƒĐŧа ĐŧĐžĐļĐĩ да ĐŊĐĩ ĐŋĐžĐēаĐļĐĩ Ņ€ĐĩĐˇŅƒĐģŅ‚Đ°Ņ‚Đ¸"</string>
<string name="revanced_hide_keyword_content_about_whole_words_title">ĐĄŅŠĐ˛ĐŋадĐĩĐŊиĐĩ ĐŊа Đ˛ŅĐ¸Ņ‡Đēи Đ´ŅƒĐŧи</string>
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<string name="revanced_hide_keyword_content_about_whole_words_summary">ĐžĐŗŅ€Đ°ĐļдаĐŊĐĩŅ‚Đž ĐŊа ĐēĐģŅŽŅ‡ĐžĐ˛Đ° Đ´ŅƒĐŧа/Ņ„Ņ€Đ°ĐˇĐ° ҁ двОКĐŊи ĐēĐ°Đ˛Đ¸Ņ‡Đēи ҉Đĩ ĐŋŅ€ĐĩĐ´ĐžŅ‚Đ˛Ņ€Đ°Ņ‚Đ¸ Ņ‡Đ°ŅŅ‚Đ¸Ņ‡ĐŊи ŅŅŠĐ˛ĐŋадĐĩĐŊĐ¸Ņ ĐŊа ĐˇĐ°ĐŗĐģĐ°Đ˛Đ¸Ņ ĐŊа видĐĩĐžĐēĐģиĐŋОвĐĩ и иĐŧĐĩĐŊа ĐŊа ĐēаĐŊаĐģи&lt;br&gt;&lt;br&gt;НаĐŋŅ€Đ¸ĐŧĐĩŅ€,&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt; ҉Đĩ ҁĐēŅ€Đ¸Đĩ видĐĩĐžĐēĐģиĐŋа: &lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt;ĐŊĐž ĐŊŅĐŧа да ҁĐēŅ€Đ¸Đĩ: &lt;b&gt;What does fair use mean?&lt;/b&gt;</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="revanced_hide_keyword_toast_invalid_common">НĐĩ ĐŧĐžĐļĐĩŅ‚Đĩ да иСĐŋĐžĐģĐˇĐ˛Đ°Ņ‚Đĩ ĐēĐģŅŽŅ‡ĐžĐ˛Đ°Ņ‚Đ° Đ´ŅƒĐŧа: %s</string>
@@ -404,7 +359,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_self_sponsor_ads_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ŅĐ°ĐŧĐžŅĐŋĐžĐŊŅĐžŅ€Đ¸Ņ€Đ°ĐŊи ĐēĐ°Ņ€Ņ‚Đ¸</string>
<string name="revanced_hide_self_sponsor_ads_summary_on">ХаĐŧĐžŅĐŋĐžĐŊŅĐžŅ€Đ¸Ņ€Đ°ĐŊĐ¸Ņ‚Đĩ ĐēĐ°Ņ€Ņ‚Đ¸ ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸</string>
<string name="revanced_hide_self_sponsor_ads_summary_off">ХаĐŧĐžŅĐŋĐžĐŊŅĐžŅ€Đ¸Ņ€Đ°ĐŊĐ¸Ņ‚Đĩ ĐēĐ°Ņ€Ņ‚Đ¸ ŅĐ° ĐŋĐžĐēаСаĐŊи</string>
<string name="revanced_hide_products_banner_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа йаĐŊĐĩŅ€Đ° Са ĐŋĐžĐēаСваĐŊĐĩ ĐŊа ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚Đ¸</string>
<string name="revanced_hide_products_banner_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа йаĐŊĐĩŅ€Đ° \"ĐŸŅ€ĐĩĐŗĐģĐĩĐ´ ĐŊа ĐŋŅ€ĐžĐ´ŅƒĐēŅ‚Đ¸\"</string>
<string name="revanced_hide_products_banner_summary_on">БаĐŊĐĩŅ€ŅŠŅ‚ Đĩ ҁĐēŅ€Đ¸Ņ‚</string>
<string name="revanced_hide_products_banner_summary_off">БаĐŊĐĩŅ€ŅŠŅ‚ Đĩ ĐŋĐžĐēаСаĐŊ</string>
<string name="revanced_hide_end_screen_store_banner_title">ĐĄĐēŅ€Đ¸Đš йаĐŊĐĩŅ€Đ° Са Ņ€ĐĩĐēĐģаĐŧа в ĐēŅ€Đ°Ņ ĐŊа ĐĩĐēŅ€Đ°ĐŊа</string>
@@ -475,9 +430,9 @@ Second \"item\" text"</string>
<string name="revanced_disable_precise_seeking_gesture_summary_off">ЖĐĩҁ҂ вĐēĐģŅŽŅ‡ĐĩĐŊ</string>
</patch>
<patch id="interaction.seekbar.enableSeekbarTappingPatch">
<string name="revanced_seekbar_tapping_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа Đ´ĐžĐēĐžŅĐ˛Đ°ĐŊĐĩŅ‚Đž ĐŊа ĐģĐĩĐŊŅ‚Đ°Ņ‚Đ° Са Đ˛Ņ€ĐĩĐŧĐĩ</string>
<string name="revanced_seekbar_tapping_summary_on">Đ¤ŅƒĐŊĐēŅ†Đ¸ŅŅ‚Đ° „ДоĐēĐžŅĐ˛Đ°ĐŊĐĩ Đ´Đž ĐģĐĩĐŊŅ‚Đ°Ņ‚Đ° Са Ņ‚ŅŠŅ€ŅĐĩĐŊĐĩ“ Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊа</string>
<string name="revanced_seekbar_tapping_summary_off">Đ¤ŅƒĐŊĐēŅ†Đ¸ŅŅ‚Đ° „ДоĐēĐžŅĐ˛Đ°ĐŊĐĩ Đ´Đž ĐģĐĩĐŊŅ‚Đ°Ņ‚Đ° Са Ņ‚ŅŠŅ€ŅĐĩĐŊĐĩ“ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊа</string>
<string name="revanced_seekbar_tapping_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа Đ´ĐžĐēĐžŅĐ˛Đ°ĐŊĐĩ Са ĐŋŅ€ĐĩĐ˛ŅŠŅ€Ņ‚Đ°ĐŊĐĩ</string>
<string name="revanced_seekbar_tapping_summary_on">ДоĐēĐžŅĐŊĐĩŅ‚Đĩ, Са да Ņ‚ŅŠŅ€ŅĐ¸Ņ‚Đĩ Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_seekbar_tapping_summary_off">ДоĐēĐžŅĐ˛Đ°ĐŊĐĩŅ‚Đž Са ĐŋŅ€ĐĩĐ˛ŅŠŅ€Ņ‚Đ°ĐŊĐĩ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
</patch>
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
<string name="revanced_swipe_brightness_title">ЗадаваĐŊĐĩ ĐŊа ŅŅ€ĐēĐžŅŅ‚ ҇ҀĐĩС ĐŋĐģŅŠĐˇĐŗĐ°ĐŊĐĩ</string>
@@ -490,9 +445,9 @@ Second \"item\" text"</string>
Đ ĐĩĐŗŅƒĐģĐ¸Ņ€Đ°ĐšŅ‚Đĩ ŅĐ¸ĐģĐ°Ņ‚Đ° ĐŊа ĐˇĐ˛ŅƒĐēа, ĐēĐ°Ņ‚Đž ĐŋĐģŅŠĐˇĐŊĐĩŅ‚Đĩ вĐĩŅ€Ņ‚Đ¸ĐēаĐģĐŊĐž ĐžŅ‚ Đ´ŅŅĐŊĐ°Ņ‚Đ° ŅŅ‚Ņ€Đ°ĐŊа ĐŊа ĐĩĐēŅ€Đ°ĐŊа"</string>
<string name="revanced_swipe_volume_summary_off">ПĐģŅŠĐˇĐŗĐ°ĐŊĐĩŅ‚Đž Са ŅĐ¸Đģа ĐŊа ĐˇĐ˛ŅƒĐēа ĐŊа Ņ†ŅĐģ ĐĩĐēŅ€Đ°ĐŊ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_swipe_press_to_engage_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐļĐĩŅŅ‚Đ° ĐŊĐ°Ņ‚Đ¸ŅĐēаĐŊĐĩ Са ĐŋŅ€ĐĩĐŧĐĩŅŅ‚Đ˛Đ°ĐŊĐĩ</string>
<string name="revanced_swipe_press_to_engage_summary_on">ПĐģŅŠĐˇĐŗĐ°ĐŊĐĩŅ‚Đž ҇ҀĐĩС ĐŊĐ°Ņ‚Đ¸ŅĐēаĐŊĐĩ Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_swipe_press_to_engage_summary_off">ПĐģŅŠĐˇĐŗĐ°ĐŊĐĩŅ‚Đž ҇ҀĐĩС ĐŊĐ°Ņ‚Đ¸ŅĐēаĐŊĐĩ Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_swipe_press_to_engage_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ĐŊĐ°Ņ‚Đ¸ŅĐēаĐŊĐĩ, Са да ĐŋĐģŅŠĐˇĐŊĐĩŅ‚Đĩ</string>
<string name="revanced_swipe_press_to_engage_summary_on">ĐĐ°Ņ‚Đ¸ŅĐēаĐŊĐĩŅ‚Đž, Са да ĐŋĐģŅŠĐˇĐŊĐĩŅ‚Đĩ, Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_swipe_press_to_engage_summary_off">ĐĐ°Ņ‚Đ¸ŅĐēаĐŊĐĩŅ‚Đž, Са да ĐŋĐģŅŠĐˇĐŊĐĩŅ‚Đĩ, Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_swipe_haptic_feedback_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа Ņ…ĐĩĐŋŅ‚Đ¸Ņ‡ĐŊĐ°Ņ‚Đ° ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа</string>
<string name="revanced_swipe_haptic_feedback_summary_on">ĐĸаĐēŅ‚Đ¸ĐģĐŊĐ°Ņ‚Đ° ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊа</string>
<string name="revanced_swipe_haptic_feedback_summary_off">ĐĸаĐēŅ‚Đ¸ĐģĐŊĐ°Ņ‚Đ° ĐžĐąŅ€Đ°Ņ‚ĐŊа Đ˛Ņ€ŅŠĐˇĐēа Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊа</string>
@@ -663,7 +618,7 @@ Second \"item\" text"</string>
<string name="revanced_hide_player_flyout_video_quality_footer_summary_off">ДоĐģĐŊĐ¸ŅŅ‚ ĐēĐžĐģĐžĐŊŅ‚Đ¸Ņ‚ŅƒĐģ ĐŊа ĐŧĐĩĐŊŅŽŅ‚Đž Са ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа видĐĩĐžŅ‚Đž ҁĐĩ ĐŋĐžĐēаСва</string>
</patch>
<patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch">
<string name="revanced_hide_player_previous_next_buttons_title">Đ‘ŅƒŅ‚ĐžĐŊи Са ĐŸŅ€ĐĩĐ´Đ¸ŅˆĐŊĐž &amp; ĐĄĐģĐĩĐ´Đ˛Đ°Ņ‰Đž видĐĩĐž</string>
<string name="revanced_hide_player_previous_next_buttons_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ĐąŅƒŅ‚ĐžĐŊĐ¸Ņ‚Đĩ \"ĐŸŅ€ĐĩĐ´Đ¸ŅˆĐĩĐŊ и ĐĄĐģĐĩĐ´Đ˛Đ°Ņ‰\"</string>
<string name="revanced_hide_player_previous_next_buttons_summary_on">Đ‘ŅƒŅ‚ĐžĐŊĐ¸Ņ‚Đĩ ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸</string>
<string name="revanced_hide_player_previous_next_buttons_summary_off">Đ‘ŅƒŅ‚ĐžĐŊĐ¸Ņ‚Đĩ ҁĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ‚</string>
<string name="revanced_hide_cast_button_title">ĐĄĐēŅ€Đ¸Đ˛Đ°ĐŊĐĩ ĐŊа ĐąŅƒŅ‚ĐžĐŊа Cast</string>
@@ -856,7 +811,6 @@ Second \"item\" text"</string>
<string name="revanced_ryd_enable_summary_on">НĐĩŅ…Đ°Ņ€ĐĩŅĐ˛Đ°ĐŊĐ¸ŅŅ‚Đ° ҁĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ‚</string>
<string name="revanced_ryd_enable_summary_off">НĐĩŅ…Đ°Ņ€ĐĩŅĐ˛Đ°ĐŊĐ¸ŅŅ‚Đ° ĐŊĐĩ ҁĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ‚</string>
<string name="revanced_ryd_shorts_title">ПоĐē. ĐŊĐĩŅ…Đ°Ņ€ĐĩŅĐ˛Đ°ĐŊĐ¸Ņ в ĐēŅ€Đ°Ņ‚ĐēĐ¸Ņ‚Đĩ ĐēĐģиĐŋОвĐĩ</string>
<string name="revanced_ryd_shorts_summary_on">НĐĩŅ…Đ°Ņ€ĐĩŅĐ˛Đ°ĐŊĐ¸ŅŅ‚Đ° ĐŊа Shorts ŅĐ° ĐŋĐžĐēаСаĐŊи</string>
<string name="revanced_ryd_shorts_summary_on_disclaimer">"НĐĩŅ…Đ°Ņ€ĐĩŅĐ˛Đ°ĐŊĐ¸ŅŅ‚Đ° ĐŊа Shorts ŅĐ° ĐŋĐžĐēаСаĐŊи
ĐžĐŗŅ€Đ°ĐŊĐ¸Ņ‡ĐĩĐŊиĐĩ: НĐĩŅ…Đ°Ņ€ĐĩŅĐ˛Đ°ĐŊĐ¸ŅŅ‚Đ° ĐŧĐžĐļĐĩ да ĐŊĐĩ ҁĐĩ ĐŋĐžĐēĐ°ĐˇĐ˛Đ°Ņ‚ в Ņ€ĐĩĐļиĐŧ иĐŊĐēĐžĐŗĐŊĐ¸Ņ‚Đž"</string>
@@ -1054,6 +1008,8 @@ Second \"item\" text"</string>
<string name="revanced_sb_vote_downvote">ĐžŅ‚Ņ€Đ¸Ņ†Đ°Ņ‚ĐĩĐģĐĩĐŊ Đ˛ĐžŅ‚</string>
<string name="revanced_sb_vote_category">ĐŸŅ€ĐžĐŧŅĐŊа ĐŊа ĐēĐ°Ņ‚ĐĩĐŗĐžŅ€Đ¸ŅŅ‚Đ°</string>
<string name="revanced_sb_vote_no_segments">ĐŅĐŧа ҁĐĩĐŗĐŧĐĩĐŊŅ‚Đ¸, Са ĐēĐžĐ¸Ņ‚Đž да ĐŗĐģĐ°ŅŅƒĐ˛Đ°Ņ‚Đĩ</string>
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<string name="revanced_sb_vote_segment_time_to_from">%1$s Đ´Đž %2$s</string>
<string name="revanced_sb_new_segment_choose_category">ИСйĐĩŅ€ĐĩŅ‚Đĩ ĐēĐ°Ņ‚ĐĩĐŗĐžŅ€Đ¸Ņ ҁĐĩĐŗĐŧĐĩĐŊŅ‚</string>
<string name="revanced_sb_new_segment_disabled_category">ĐšĐ°Ņ‚ĐĩĐŗĐžŅ€Đ¸ŅŅ‚Đ° Đĩ иСĐēĐģ. в ĐŊĐ°ŅŅ‚Ņ€ĐžĐšĐēĐ¸Ņ‚Đĩ. ВĐēĐģ. Ņ Са да ĐŧĐžĐļĐĩŅ‚Đĩ да иСĐŋŅ€Đ°Ņ‚Đ¸Ņ‚Đĩ.</string>
<string name="revanced_sb_new_segment_title">Нова Ņ‡Đ°ŅŅ‚ в SponsorBlock</string>
@@ -1101,6 +1057,7 @@ Second \"item\" text"</string>
<string name="revanced_sb_stats_saved_hour_format">%1$s Ņ‡Đ°ŅĐžĐ˛Đĩ %2$s ĐŧиĐŊŅƒŅ‚Đ¸</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s ĐŧиĐŊŅƒŅ‚Đ¸ %2$s ҁĐĩĐē҃ĐŊди</string>
<string name="revanced_sb_stats_saved_second_format">%s ҁĐĩĐē҃ĐŊди</string>
<string name="revanced_sb_color_opacity_label">НĐĩĐŋŅ€ĐžĐˇŅ€Đ°Ņ‡ĐŊĐžŅŅ‚:</string>
<string name="revanced_sb_color_dot_label">ĐĻĐ˛ŅŅ‚:</string>
<string name="revanced_sb_color_changed">ĐĻвĐĩŅ‚ŅŠŅ‚ Đĩ ĐŋŅ€ĐžĐŧĐĩĐŊĐĩĐŊ</string>
<string name="revanced_sb_color_reset">Đ’ŅŠĐˇŅŅ‚Đ°ĐŊОви Ņ†Đ˛ĐĩŅ‚Đ°</string>
@@ -1121,11 +1078,9 @@ Second \"item\" text"</string>
ĐžŅ„ĐžŅ€ĐŧĐģĐĩĐŊиĐĩ Са Ņ‚Đ°ĐąĐģĐĩŅ‚
â€ĸ ĐŸŅƒĐąĐģиĐēĐ°Ņ†Đ¸Đ¸Ņ‚Đĩ ĐŊа ĐžĐąŅ‰ĐŊĐžŅŅ‚Ņ‚Đ° ŅĐ° ҁĐēŅ€Đ¸Ņ‚Đ¸
ĐžŅ„ĐžŅ€ĐŧĐģĐĩĐŊиĐĩ Са Đ°Đ˛Ņ‚ĐžĐŧОйиĐģ
â€ĸ МĐĩĐŊŅŽŅ‚Đž â€žĐ˜ŅŅ‚ĐžŅ€Đ¸Ņ ĐŊа ĐŗĐģĐĩдаĐŊĐĩ“ Đĩ ҁĐēŅ€Đ¸Ņ‚Đž
â€ĸ РаСдĐĩĐģŅŠŅ‚ â€žĐ Đ°ĐˇĐŗĐģĐĩдай“ Đĩ Đ˛ŅŠĐˇŅŅ‚Đ°ĐŊОвĐĩĐŊ
ĐĐ˛Ņ‚ĐžĐŧОйиĐģĐŊĐž ĐžŅ„ĐžŅ€ĐŧĐģĐĩĐŊиĐĩ
â€ĸ Shorts ҁĐĩ ĐžŅ‚Đ˛Đ°Ņ€ŅŅ‚ в ОйиĐēĐŊОвĐĩĐŊĐ¸Ņ ĐŋĐģĐĩĐšŅŠŅ€
â€ĸ ЛĐĩĐŊŅ‚Đ°Ņ‚Đ° Đĩ ĐžŅ€ĐŗĐ°ĐŊĐ¸ĐˇĐ¸Ņ€Đ°ĐŊа ĐŋĐž Ņ‚ĐĩĐŧи и ĐēаĐŊаĐģ"</string>
â€ĸ КаĐŊаĐģŅŠŅ‚ Đĩ ĐžŅ€ĐŗĐ°ĐŊĐ¸ĐˇĐ¸Ņ€Đ°ĐŊ ĐŋĐž Ņ‚ĐĩĐŧи и ĐēаĐŊаĐģи"</string>
</patch>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<string name="revanced_spoof_app_version_title">ПодĐģŅŠĐŗĐ˛Đ°ĐŊĐĩ Са вĐĩŅ€ŅĐ¸ŅŅ‚Đ° ĐŊа ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩŅ‚Đž</string>
@@ -1140,12 +1095,7 @@ Second \"item\" text"</string>
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<string name="revanced_spoof_app_version_target_title">ПодĐģŅŠĐŗĐ˛Đ°ĐŊĐĩ Са вĐĩŅ€ŅĐ¸ŅŅ‚Đ° ĐŊа</string>
<string name="revanced_spoof_app_version_target_entry_1">19.35.36 - Đ’ŅŠĐˇŅŅ‚Đ°ĐŊОвĐĩŅ‚Đĩ ŅŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ иĐēĐžĐŊи ĐŊа Shorts в ĐŋĐģĐĩĐšŅŠŅ€Đ°</string>
<string name="revanced_spoof_app_version_target_entry_2">19.26.42 - Đ’ŅŠĐˇŅŅ‚Đ°ĐŊĐžĐ˛ŅĐ˛Đ°ĐŊĐĩ ĐŊа ŅŅ‚Đ°Ņ€Đ¸Ņ‚Đĩ иĐēĐžĐŊи Са ĐŊĐ°Đ˛Đ¸ĐŗĐ°Ņ†Đ¸Ņ</string>
<!-- 'RYD' is 'Return YouTube Dislike' -->
<string name="revanced_spoof_app_version_target_legacy_entry_1">18.33.40 - Đ’ŅŠĐˇŅŅ‚Đ°ĐŊОвĐĩŅ‚Đĩ RYD в Ņ€ĐĩĐļиĐŧ „иĐŊĐēĐžĐŗĐŊĐ¸Ņ‚Đžâ€œ ĐŊа Shorts</string>
<string name="revanced_spoof_app_version_target_legacy_entry_2">18.20.39 - Đ’ŅŠĐˇŅŅ‚Đ°ĐŊĐžĐ˛ŅĐ˛Đ°ĐŊĐĩ ĐŊа видĐĩĐž ҁĐēĐžŅ€ĐžŅŅ‚ &amp; в ĐŧĐĩĐŊŅŽŅ‚Đž Са ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž</string>
<string name="revanced_spoof_app_version_target_legacy_entry_3">18.09.39 - Đ’ŅŠĐˇŅŅ‚Đ°ĐŊĐžĐ˛ŅĐ˛Đ°ĐŊĐĩ ĐŊа Ņ‚Đ°Đą \"БибĐģĐ¸ĐžŅ‚ĐĩĐēа\"</string>
<string name="revanced_spoof_app_version_target_legacy_entry_4">17.33.42 - Đ’Ņ€ŅŠŅ‰Đ°ĐŊĐĩ ĐŊа ҁĐĩĐēŅ†Đ¸ŅŅ‚Đ° ҁ ĐŋĐģĐĩĐšĐģĐ¸ŅŅ‚Đ° ĐēҊĐŧ ŅŅ‚Đ°Ņ€Đ¸Ņ ŅŅ‚Đ¸Đģ</string>
<string name="revanced_spoof_app_version_target_entry_2">19.01.34 - Đ’ŅŠĐˇŅŅ‚Đ°ĐŊĐžĐ˛ŅĐ˛Đ°ĐŊĐĩ ĐŊа ŅŅ‚Đ°Ņ€Đ¸ иĐēĐžĐŊи Са ĐŊĐ°Đ˛Đ¸ĐŗĐ°Ņ†Đ¸Ņ</string>
</patch>
<patch id="layout.startpage.changeStartPagePatch">
<string name="revanced_change_start_page_title">Задай ĐŊĐ°Ņ‡Đ°ĐģĐŊа ŅŅ‚Ņ€Đ°ĐŊĐ¸Ņ†Đ°</string>
@@ -1195,7 +1145,7 @@ Second \"item\" text"</string>
</patch>
<patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">МиĐŊиĐŧĐ¸ĐˇĐ¸Ņ€Đ°ĐŊ ĐĩĐēŅ€Đ°ĐŊ Са Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩ</string>
<string name="revanced_miniplayer_screen_summary">ĐŸŅ€ĐžĐŧĐĩĐŊĐĩŅ‚Đĩ ŅŅ‚Đ¸Đģа ĐŊа ĐŧиĐŊиĐŧĐ¸ĐˇĐ¸Ņ€Đ°ĐŊĐ¸Ņ ĐĩĐēŅ€Đ°ĐŊ Са Đ˛ŅŠĐˇĐŋŅ€ĐžĐ¸ĐˇĐ˛ĐĩĐļдаĐŊĐĩ</string>
<string name="revanced_miniplayer_screen_summary">ĐŸŅ€ĐžĐŧŅĐŊа ĐŊа ŅŅ‚Đ¸Đģа ĐŊа ĐŧиĐŊиĐŧĐ¸ĐˇĐ¸Ņ€Đ°ĐŊ ĐŋĐģĐĩĐšŅŠŅ€ в ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩŅ‚Đž</string>
<string name="revanced_miniplayer_type_title">МиĐŊиĐŧĐ¸ĐˇĐ¸Ņ€Đ°ĐŊ Ņ‚Đ¸Đŋ ĐĩĐēŅ€Đ°ĐŊ Са ĐŗĐģĐĩдаĐŊĐĩ</string>
<string name="revanced_miniplayer_type_entry_0">ДĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_miniplayer_type_entry_1">По ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ</string>
@@ -1248,8 +1198,6 @@ Second \"item\" text"</string>
<string name="revanced_gradient_loading_screen_title">ФОĐŊ ĐŊа ĐĩĐēŅ€Đ°ĐŊа ĐŋŅ€Đ¸ ĐˇĐ°Ņ€ĐĩĐļдаĐŊĐĩ ĐŊа видĐĩĐž</string>
<string name="revanced_gradient_loading_screen_summary_on">ЕĐēŅ€Đ°ĐŊŅŠŅ‚ Са ĐˇĐ°Ņ€ĐĩĐļдаĐŊĐĩ ҉Đĩ иĐŧа ĐŗŅ€Đ°Đ´Đ¸ĐĩĐŊŅ‚ĐĩĐŊ Ņ„ĐžĐŊ</string>
<string name="revanced_gradient_loading_screen_summary_off">ЕĐēŅ€Đ°ĐŊŅŠŅ‚ Са ĐˇĐ°Ņ€ĐĩĐļдаĐŊĐĩ ҉Đĩ иĐŧа ĐŋĐģŅŠŅ‚ĐĩĐŊ Ņ„ĐžĐŊ</string>
</patch>
<patch id="layout.theme.themeResourcePatch">
<string name="revanced_seekbar_custom_color_title">ĐŸŅ€ĐžĐŧŅĐŊа ĐŊа Ņ†Đ˛ĐĩŅ‚Đ° ĐŊа иĐŊдиĐēĐ°Ņ‚ĐžŅ€Đ° Са Đ˛Ņ€ĐĩĐŧĐĩ</string>
<string name="revanced_seekbar_custom_color_summary_on">ПоĐēаСва ҁĐĩ ĐŋĐĩŅ€ŅĐžĐŊаĐģĐ¸ĐˇĐ¸Ņ€Đ°ĐŊ Ņ†Đ˛ŅŅ‚ ĐŊа ĐģĐĩĐŊŅ‚Đ°Ņ‚Đ° Са ĐŊаĐŋŅ€ĐĩĐ´ŅŠĐē</string>
<string name="revanced_seekbar_custom_color_summary_off">ПоĐēаСва ҁĐĩ ĐžŅ€Đ¸ĐŗĐ¸ĐŊаĐģĐŊĐ¸Ņ Ņ†Đ˛ŅŅ‚ ĐŊа ĐģĐĩĐŊŅ‚Đ°Ņ‚Đ° Са ĐŊаĐŋŅ€ĐĩĐ´ŅŠĐē</string>
@@ -1341,8 +1289,8 @@ Second \"item\" text"</string>
</patch>
<patch id="misc.links.openLinksExternallyPatch">
<string name="revanced_external_browser_title">ĐžŅ‚Đ˛Đ°Ņ€ŅĐŊĐĩ ĐŊа Đ˛Ņ€ŅŠĐˇĐēи в ĐąŅ€Đ°ŅƒĐˇŅŠŅ€Đ°</string>
<string name="revanced_external_browser_summary_on">ĐžŅ‚Đ˛Đ°Ņ€ŅĐŊĐĩ ĐŊа Đ˛ŅŠĐŊ҈ĐŊи Đ˛Ņ€ŅŠĐˇĐēи</string>
<string name="revanced_external_browser_summary_off">ĐžŅ‚Đ˛Đ°Ņ€ŅĐŊĐĩ ĐŊа Đ˛Ņ€ŅŠĐˇĐēи в ĐŋŅ€Đ¸ĐģĐžĐļĐĩĐŊиĐĩŅ‚Đž</string>
<string name="revanced_external_browser_summary_on">ĐžŅ‚Đ˛Đ°Ņ€ŅĐŊĐĩ ĐŊа Đ˛Ņ€ŅŠĐˇĐēи Đ˛ŅŠĐ˛ Đ˛ŅŠĐŊ҈ĐĩĐŊ ĐąŅ€Đ°ŅƒĐˇŅŠŅ€</string>
<string name="revanced_external_browser_summary_off">ĐžŅ‚Đ˛Đ°Ņ€ŅĐŊĐĩ ĐŊа Đ˛Ņ€ŅŠĐˇĐēи Đ˛ŅŠĐ˛ Đ˛ĐŗŅ€Đ°Đ´ĐĩĐŊ ĐąŅ€Đ°ŅƒĐˇŅŠŅ€</string>
</patch>
<patch id="misc.privacy.removeTrackingQueryParameterPatch">
<string name="revanced_remove_tracking_query_parameter_title">ĐŸŅ€ĐĩĐŧĐ°Ņ…ĐŊĐĩŅ‚Đĩ ĐŋĐ°Ņ€Đ°ĐŧĐĩŅ‚ŅŠŅ€Đ° ĐŊа ĐˇĐ°ŅĐ˛ĐēĐ°Ņ‚Đ° Са ĐŋŅ€ĐžŅĐģĐĩĐ´ŅĐ˛Đ°ĐŊĐĩ</string>
@@ -1369,9 +1317,15 @@ Second \"item\" text"</string>
<string name="revanced_remember_video_quality_last_selected_summary_off">ĐŸŅ€ĐžĐŧĐĩĐŊĐ¸Ņ‚Đĩ в ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛ĐžŅ‚Đž ҁĐĩ ĐžŅ‚ĐŊĐ°ŅŅŅ‚ ŅĐ°ĐŧĐž Са Ņ‚ĐĩĐēŅƒŅ‰Đ¸Ņ видĐĩĐžĐēĐģиĐŋ</string>
<string name="revanced_video_quality_default_wifi_title">ĐŸŅ€ĐĩĐ´ĐŋĐžŅ‡Đ¸Ņ‚Đ°ĐŊĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŋŅ€Đ¸ Wi-Fi</string>
<string name="revanced_video_quality_default_mobile_title">ĐŸŅ€ĐĩĐ´ĐŋĐžŅ‡Đ¸Ņ‚Đ°ĐŊĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŋŅ€Đ¸ ĐŧОйиĐģĐŊи даĐŊĐŊи</string>
<string name="revanced_remember_shorts_quality_last_selected_title">ЗаĐŋĐžĐŧĐŊŅĐŊĐĩ ĐŊа ĐŋŅ€ĐžĐŧĐĩĐŊĐ¸Ņ‚Đĩ в ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛ĐžŅ‚Đž ĐŊа Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">ĐŸŅ€ĐžĐŧĐĩĐŊĐ¸Ņ‚Đĩ в ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛ĐžŅ‚Đž ҁĐĩ ĐŋŅ€Đ¸ĐģĐ°ĐŗĐ°Ņ‚ Са Đ˛ŅĐ¸Ņ‡Đēи Shorts</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">ĐŸŅ€ĐžĐŧĐĩĐŊĐ¸Ņ‚Đĩ в ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛ĐžŅ‚Đž ҁĐĩ ĐŋŅ€Đ¸ĐģĐ°ĐŗĐ°Ņ‚ ŅĐ°ĐŧĐž Са Ņ‚ĐĩĐēŅƒŅ‰Đ¸Ņ Short</string>
<string name="revanced_shorts_quality_default_wifi_title">ĐšĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ ĐŊа Shorts Đ˛ŅŠĐ˛ Wi-Fi ĐŧŅ€ĐĩĐļа</string>
<string name="revanced_shorts_quality_default_mobile_title">ĐšĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŋĐž ĐŋĐžĐ´Ņ€Đ°ĐˇĐąĐ¸Ņ€Đ°ĐŊĐĩ ĐŊа Shorts в ĐŧОйиĐģĐŊа ĐŧŅ€ĐĩĐļа</string>
<string name="revanced_remember_video_quality_mobile">ĐŧОйиĐģĐŊи даĐŊĐŊи</string>
<string name="revanced_remember_video_quality_wifi">wi-fi</string>
<string name="revanced_remember_video_quality_toast">ĐŸŅ€ĐžĐŧĐĩĐŊĐĩĐŊĐž ŅŅ‚Đ°ĐŊĐ´Đ°Ņ€Ņ‚ĐŊĐž %1$s ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа: %2$s</string>
<string name="revanced_remember_video_quality_toast_shorts">ĐŸŅ€ĐžĐŧĐĩĐŊĐĩĐŊĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа Shorts %1$s ĐŊа: %2$s</string>
</patch>
<patch id="video.speed.button.playbackSpeedButtonPatch">
<string name="revanced_playback_speed_dialog_button_title">ПоĐēаСваĐŊĐĩ ĐąŅƒŅ‚ĐžĐŊ Са ҁĐēĐžŅ€ĐžŅŅ‚</string>
@@ -1402,10 +1356,10 @@ Second \"item\" text"</string>
<string name="revanced_disable_hdr_video_summary_on">HDR видĐĩĐžŅ‚Đž Đĩ Đ´ĐĩаĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
<string name="revanced_disable_hdr_video_summary_off">HDR видĐĩĐžŅ‚Đž Đĩ аĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐž</string>
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<string name="revanced_restore_old_video_quality_menu_title">Đ’ŅŠĐˇŅŅ‚Đ°ĐŊОвĐĩŅ‚Đĩ ŅŅ‚Đ°Ņ€ĐžŅ‚Đž ĐŧĐĩĐŊŅŽ Са ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа видĐĩĐžŅ‚Đž</string>
<string name="revanced_restore_old_video_quality_menu_summary_on">ПоĐēаСва ҁĐĩ ŅŅ‚Đ°Ņ€ĐžŅ‚Đž ĐŧĐĩĐŊŅŽ Са видĐĩĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž</string>
<string name="revanced_restore_old_video_quality_menu_summary_off">ĐĄŅ‚Đ°Ņ€ĐžŅ‚Đž ĐŧĐĩĐŊŅŽ Са видĐĩĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž Đĩ ҁĐēŅ€Đ¸Ņ‚Đž</string>
<patch id="video.quality.advancedVideoQualityMenuPatch">
<string name="revanced_advanced_video_quality_menu_title">ПоĐēаСваĐŊĐĩ ĐŊа ĐŧĐĩĐŊŅŽŅ‚Đž Са Ņ€Đ°ĐˇŅˆĐ¸Ņ€ĐĩĐŊĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа видĐĩĐžŅ‚Đž</string>
<string name="revanced_advanced_video_quality_menu_summary_on">ПоĐēаСва ҁĐĩ ĐŧĐĩĐŊŅŽŅ‚Đž Са Ņ€Đ°ĐˇŅˆĐ¸Ņ€ĐĩĐŊĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа видĐĩĐžŅ‚Đž</string>
<string name="revanced_advanced_video_quality_menu_summary_off">МĐĩĐŊŅŽŅ‚Đž Са Ņ€Đ°ĐˇŅˆĐ¸Ņ€ĐĩĐŊĐž ĐēĐ°Ņ‡ĐĩŅŅ‚Đ˛Đž ĐŊа видĐĩĐžŅ‚Đž ĐŊĐĩ ҁĐĩ ĐŋĐžĐēаСва</string>
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
<string name="revanced_slide_to_seek_title">АĐēŅ‚Đ¸Đ˛Đ¸Ņ€Đ°ĐŊĐĩ ĐŊа ҁĐģаКд Са ĐŋŅ€ĐĩĐ˛ŅŠŅ€Ņ‚Đ°ĐŊĐĩ</string>

View File

@@ -48,57 +48,6 @@ Second \"item\" text"</string>
āύāϤ⧁āύ āĻ­āĻžāώāĻž āĻ…āύ⧁āĻŦāĻžāĻĻ āĻ•āϰāϤ⧇ translate.revanced.app āĻĻ⧇āϖ⧁āύ"</string>
<string name="revanced_language_DEFAULT">āĻ…ā§āϝāĻžāĻĒā§āϞāĻŋāϕ⧇āĻļāύ⧇āϰ āĻ­āĻžāώāĻž</string>
<string name="revanced_language_AR">āφāϰāĻŦāĻŋ</string>
<string name="revanced_language_AZ">āφāϜāĻžāϰāĻŦāĻžāχāϜāĻžāύāĻŋ</string>
<string name="revanced_language_BG">āĻŦ⧁āϞāϗ⧇āϰāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_BN">āĻŦāĻžāĻ‚āϞāĻž</string>
<string name="revanced_language_CA">āĻ•āĻžāϤāĻžāϞāĻžāύ</string>
<string name="revanced_language_CS">āĻšā§‡āĻ•</string>
<string name="revanced_language_DA">āĻĄā§āϝāĻžāύāĻŋāĻļ</string>
<string name="revanced_language_DE">āϜāĻžāĻ°ā§āĻŽāĻžāύ</string>
<string name="revanced_language_EL">āĻ—ā§āϰāĻŋāĻ•</string>
<string name="revanced_language_EN">āχāĻ‚āϰ⧇āϜāĻŋ</string>
<string name="revanced_language_ES">āĻ¸ā§āĻĒā§āϝāĻžāύāĻŋāĻļ</string>
<string name="revanced_language_ET">āĻāĻ¸ā§āϤ⧋āύāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_FA">āĻĢāĻžāĻ°ā§āϏāĻŋ</string>
<string name="revanced_language_FI">āĻĢāĻŋāύāĻŋāĻļ</string>
<string name="revanced_language_FR">āĻĢāϰāĻžāϏāĻŋ</string>
<string name="revanced_language_GU">āϗ⧁āϜāϰāĻžāϟāĻŋ</string>
<string name="revanced_language_HI">āĻšāĻŋāĻ¨ā§āĻĻāĻŋ</string>
<string name="revanced_language_HR">āĻ•ā§āϰ⧋āϝāĻŧ⧇āĻļā§€āϝāĻŧ</string>
<string name="revanced_language_HU">āĻšāĻžāĻ™ā§āϗ⧇āϰāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_ID">āχāĻ¨ā§āĻĻā§‹āύ⧇āĻļāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_IT">āχāϤāĻžāϞ⧀āϝāĻŧ</string>
<string name="revanced_language_JA">āϜāĻžāĻĒāĻžāύāĻŋ</string>
<string name="revanced_language_KK">āĻ•āĻžāϜāĻžāĻ–</string>
<string name="revanced_language_KO">āϕ⧋āϰāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_LT">āϞāĻŋāĻĨ⧁⧟āĻžāύāĻŋ⧟āĻžāύ</string>
<string name="revanced_language_LV">āϞāĻžāϤāĻ­āĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_MK">āĻŽā§āϝāĻžāϏ⧇āĻĄā§‹āύāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_MN">āĻŽāĻ™ā§āĻ—ā§‹āϞ⧀āϝāĻŧ</string>
<string name="revanced_language_MR">āĻŽāĻžāϰāĻžāĻ āĻŋ</string>
<string name="revanced_language_MS">āĻŽāĻžāϞāϝāĻŧ</string>
<string name="revanced_language_MY">āĻŦāĻ°ā§āĻŽāĻŋ</string>
<string name="revanced_language_NL">āĻĄāĻžāϚ</string>
<string name="revanced_language_OR">āĻ“āĻĄāĻŧāĻŋāϝāĻŧāĻž</string>
<string name="revanced_language_PA">āĻĒāĻžāĻžā§āϜāĻžāĻŦāĻŋ</string>
<string name="revanced_language_PL">āĻĒā§‹āϞāĻŋāĻļ</string>
<string name="revanced_language_PT">āĻĒāĻ°ā§āϤ⧁āĻ—āĻŋāϜ</string>
<string name="revanced_language_RO">āϰ⧋āĻŽāĻžāύ⧀āϝāĻŧ</string>
<string name="revanced_language_RU">āϰ⧁āĻļ</string>
<string name="revanced_language_SK">āĻ¸ā§āϞ⧋āĻ­āĻžāĻ•</string>
<string name="revanced_language_SL">āĻ¸ā§āϞ⧋āϭ⧇āύ</string>
<string name="revanced_language_SR">āϏāĻžāĻ°ā§āĻŦāĻŋāϝāĻŧāĻžāύ</string>
<string name="revanced_language_SV">āϏ⧁āχāĻĄāĻŋāĻļ</string>
<string name="revanced_language_SW">āϏ⧋āϝāĻŧāĻžāĻšāĻŋāϞāĻŋ</string>
<string name="revanced_language_TA">āϤāĻžāĻŽāĻŋāϞ</string>
<string name="revanced_language_TE">āϤ⧇āϞ⧁āϗ⧁</string>
<string name="revanced_language_TH">āĻĨāĻžāχ</string>
<string name="revanced_language_TR">āϤ⧁āĻ°ā§āĻ•āĻŋ</string>
<string name="revanced_language_UK">āχāωāĻ•ā§āϰ⧇āύ⧀āϝāĻŧ</string>
<string name="revanced_language_UR">āωāĻ°ā§āĻĻ⧁</string>
<string name="revanced_language_VI">āĻ­āĻŋāϝāĻŧ⧇āϤāύāĻžāĻŽā§€</string>
<string name="revanced_language_ZH">āϚāĻžāχāύāĻŋāϜ</string>
<string name="revanced_pref_import_export_title">āφāĻŽāĻĻāĻžāύāĻŋ āĻāĻŦāĻ‚ āϰāĻĒā§āϤāĻžāύāĻŋ</string>
<string name="revanced_pref_import_export_summary">ReVanced āϏ⧇āϟāĻŋāĻ‚ āφāĻŽāĻĻāĻžāύāĻŋ āĻŦāĻž āϰāĻĒā§āϤāĻžāύāĻŋ āĻ•āϰ⧁āύ</string>
<!-- Settings about dialog. -->
@@ -277,6 +226,9 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_artist_cards_title">āφāĻ°ā§āϟāĻŋāĻ¸ā§āϟ āĻ•āĻžāĻ°ā§āĻĄ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_artist_cards_summary_on">āφāĻ°ā§āϟāĻŋāĻ¸ā§āϟ āĻ•āĻžāĻ°ā§āĻĄ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_artist_cards_summary_off">āφāĻ°ā§āϟāĻŋāĻ¸ā§āϟ āĻ•āĻžāĻ°ā§āĻĄ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_ai_generated_video_summary_section_title">\'AI-āĻœā§‡āύāĻžāϰ⧇āĻŸā§‡āĻĄ āĻ­āĻŋāĻĄāĻŋāĻ“ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ\' āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_on">āĻ­āĻŋāĻĄāĻŋāĻ“ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ āĻŦāĻŋāĻ­āĻžāĻ— āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_ai_generated_video_summary_section_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ āĻŦāĻŋāĻ­āĻžāĻ— āĻĻ⧇āĻ–āĻžāύ⧋ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_attributes_section_title">āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāĻžāĻŦāϞ⧀ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_attributes_section_summary_on">āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāϝ⧁āĻ•ā§āϤ āĻ¸ā§āĻĨāĻžāύ, āϗ⧇āĻŽāϏ, āϏāĻ™ā§āĻ—ā§€āϤ, āĻāĻŦāĻ‚ āωāĻ˛ā§āϞāĻŋāĻ–āĻŋāϤ āĻŦā§āϝāĻ•ā§āϤāĻŋ āĻŦāĻŋāĻ­āĻžāĻ—āϗ⧁āϞāĻŋ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_attributes_section_summary_off">āĻŦ⧈āĻļāĻŋāĻˇā§āĻŸā§āϝāϝ⧁āĻ•ā§āϤ āĻ¸ā§āĻĨāĻžāύ, āϗ⧇āĻŽāϏ, āϏāĻ™ā§āĻ—ā§€āϤ, āĻāĻŦāĻ‚ āωāĻ˛ā§āϞāĻŋāĻ–āĻŋāϤ āĻŦā§āϝāĻ•ā§āϤāĻŋ āĻŦāĻŋāĻ­āĻžāĻ—āϗ⧁āϞāĻŋ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇</string>
@@ -301,6 +253,7 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_description_components_screen_title">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āĻŦāĻŋāĻŦāϰāĻŖ</string>
<string name="revanced_hide_description_components_screen_summary">āĻ­āĻŋāĻĄāĻŋāĻ“ āĻŦāĻŋāĻŦāϰāĻŖ āĻāϰ āωāĻĒāĻžāĻĻāĻžāύ āϞ⧁āĻ•āĻžāύ āĻŦāĻž āĻĒā§āϰāĻĻāĻ°ā§āĻļāύ āĻ•āϰ⧁āύ</string>
<string name="revanced_hide_filter_bar_screen_title">āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻŦāĻžāϰ</string>
<string name="revanced_hide_filter_bar_screen_summary">āĻĢāĻŋāĻĄ, āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ⧇āϰ āĻĢāϞāĻžāĻĢāϞ āĻāĻŦāĻ‚ āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ āĻ­āĻŋāĻĄāĻŋāĻ“āϗ⧁āϞ⧋āϤ⧇ āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻŦāĻžāϰ āϞ⧁āĻ•āĻžāύ āĻ…āĻĨāĻŦāĻž āĻĻ⧇āĻ–āĻžāύ</string>
<string name="revanced_hide_filter_bar_feed_in_feed_title">āĻĢāĻŋāĻĄā§‡ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_filter_bar_feed_in_feed_summary_on">āĻĢāĻŋāĻĄā§‡ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_filter_bar_feed_in_feed_summary_off">āĻĢāĻŋāĻĄā§‡ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
@@ -312,9 +265,12 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ āĻ­āĻŋāĻĄāĻŋāĻ“āϤ⧇ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_comments_screen_title">āĻŽāĻ¨ā§āϤāĻŦā§āϝ</string>
<string name="revanced_comments_screen_summary">āĻŽāĻ¨ā§āϤāĻŦā§āϝ āĻŦāĻŋāĻ­āĻžāϗ⧇āϰ āωāĻĒāĻžāĻĻāĻžāύāϗ⧁āϞāĻŋ āϞ⧁āĻ•āĻžāύ āĻŦāĻž āĻĻ⧇āĻ–āĻžāύ⧎</string>
<string name="revanced_hide_comments_chat_summary_title">\'Chat summary\' āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_comments_chat_summary_summary_on">āĻšā§āϝāĻžāϟ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_comments_chat_summary_summary_off">āĻšā§āϝāĻžāϟ āϏāĻžāϰāϏāĻ‚āĻ•ā§āώ⧇āĻĒ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_hide_comments_ai_chat_summary_title">āĻāφāχ āĻšā§āϝāĻžāϟ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤāϏāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_on">āĻšā§āϝāĻžāϟ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤāϏāĻžāϰ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_comments_ai_chat_summary_summary_off">āĻšā§āϝāĻžāϟ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤāϏāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_comments_ai_summary_title">āĻāφāχ āĻŽāĻ¨ā§āϤāĻŦā§āϝ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤāϏāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_comments_ai_summary_summary_on">āĻŽāĻ¨ā§āϤāĻŦā§āϝ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤāϏāĻžāϰ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_comments_ai_summary_summary_off">āĻŽāĻ¨ā§āϤāĻŦā§āϝ āϏāĻ‚āĻ•ā§āώāĻŋāĻĒā§āϤāϏāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_comments_by_members_header_title">\'āĻŽā§‡āĻŽā§āĻŦāĻžāϰāĻĻ⧇āϰ āĻŽāĻ¨ā§āϤāĻŦā§āϝ\' āĻšā§‡āĻĄāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_comments_by_members_header_summary_on">āϏāĻĻāĻ¸ā§āϝāĻĻ⧇āϰ āĻĻā§āĻŦāĻžāϰāĻž āĻŽāĻ¨ā§āϤāĻŦā§āϝ āĻšā§‡āĻĄāĻžāϰ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_comments_by_members_header_summary_off">āϏāĻĻāĻ¸ā§āϝāĻĻ⧇āϰ āĻĻā§āĻŦāĻžāϰāĻž āĻŽāĻ¨ā§āϤāĻŦā§āϝ āĻšā§‡āĻĄāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇</string>
@@ -361,7 +317,7 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_keyword_content_subscriptions_summary_on">āϏāĻžāĻŦāĻ¸ā§āĻ•ā§āϰāĻŋāĻĒāĻļāύ āĻĒāĻžāϤāĻžāϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻĻā§āĻŦāĻžāϰāĻž āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_keyword_content_subscriptions_summary_off">āϏāĻžāĻŦāĻ¸ā§āĻ•ā§āϰāĻŋāĻĒāĻļāύ āĻĒāĻžāϤāĻžāϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻĻā§āĻŦāĻžāϰāĻž āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻ•āϰāĻž āĻšā§ŸāύāĻŋ</string>
<string name="revanced_hide_keyword_content_phrases_title">āϞ⧁āĻ•āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ</string>
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
<!-- For localization, it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<string name="revanced_hide_keyword_content_phrases_summary">"āύāϤ⧁āύ āϞāĻžāχāύ āĻĻā§āĻŦāĻžāϰāĻž āĻĒ⧃āĻĨāĻ• āĻ•āϰāĻž āϞ⧁āĻ•āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āĻ•āĻŋāĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻāĻŦāĻ‚ āĻŦāĻžāĻ•ā§āϝāĻžāĻ‚āĻļ
@@ -376,7 +332,7 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
â€ĸ āĻ•āĻŋāϛ⧁ UI āωāĻĒāĻžāĻĻāĻžāύ āϞ⧁āĻ•āĻžāύ⧋ āύāĻžāĻ“ āĻšāϤ⧇ āĻĒāĻžāϰ⧇
â€ĸ āϕ⧋āύāĻ“ āĻ•āĻŋāĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻ•āϰāϞ⧇ āϕ⧋āύāĻ“ āĻĢāϞāĻžāĻĢāϞ āύāĻžāĻ“ āĻĻ⧇āĻ–āĻžāϤ⧇ āĻĒāĻžāϰ⧇"</string>
<string name="revanced_hide_keyword_content_about_whole_words_title">āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻļāĻŦā§āĻĻ āĻŽā§‡āϞāĻžāĻ“</string>
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<!-- Translations _must_ use a localized example. For languages that do not use spaces between words (Chinese, Japanese, etc.) the English AI example should be used since no localized examples exist. Or if using machine translations, or if nobody wants to think of a localized example, then the English 'ai' example should be left as-is. -->
<string name="revanced_hide_keyword_content_about_whole_words_summary">āĻĄāĻžāĻŦāϞ āϕ⧋āĻŸā§‡āϰ āĻŽāĻ§ā§āϝ⧇ āĻāĻ•āϟāĻŋ āϕ⧀āĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ/āĻĢā§āϰ⧇āϜ āϰāĻžāĻ–āϞ⧇ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻļāĻŋāϰ⧋āύāĻžāĻŽ āĻāĻŦāĻ‚ āĻšā§āϝāĻžāύ⧇āϞ⧇āϰ āύāĻžāĻŽā§‡āϰ āφāĻ‚āĻļāĻŋāĻ• āĻŽāĻŋāϞ āϏāύāĻžāĻ•ā§āϤ āĻ•āϰāĻž āĻŦāĻ¨ā§āϧ āĻšā§Ÿā§‡ āϝāĻžāĻŦ⧇&lt;br&gt;&lt;br&gt;āωāĻĻāĻžāĻšāϰāĻŖāĻ¸ā§āĻŦāϰ⧂āĻĒ,&lt;br&gt;&lt;b&gt;\"ai\"&lt;/b&gt; āĻ­āĻŋāĻĄāĻŋāĻ“āϟāĻŋ āϞ⧁āĻ•āĻŋāϝāĻŧ⧇ āĻĻ⧇āĻŦ⧇: &lt;b&gt;How does AI work?&lt;/b&gt;&lt;br&gt;āĻ•āĻŋāĻ¨ā§āϤ⧁ āϞ⧁āĻ•āĻŋāϝāĻŧ⧇ āĻĻ⧇āĻŦ⧇ āύāĻž: &lt;b&gt;What does fair use mean?&lt;/b&gt;</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="revanced_hide_keyword_toast_invalid_common">āĻ•āĻŋāĻ“āϝāĻŧāĻžāĻ°ā§āĻĄ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāĻž āϝāĻžāĻŦ⧇ āύāĻž: %s</string>
@@ -403,7 +359,7 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_self_sponsor_ads_title">āĻ¸ā§āĻŦ-āĻ¸ā§āĻĒāĻ¨ā§āϏāϰ āĻ•āĻžāĻ°ā§āĻĄ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_self_sponsor_ads_summary_on">āĻ¸ā§āĻŦ-āĻ¸ā§āĻĒāĻ¨ā§āϏāϰ āĻ•āĻžāĻ°ā§āĻĄ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_self_sponsor_ads_summary_off">āĻ¸ā§āĻŦ-āĻ¸ā§āĻĒāĻ¨ā§āϏāϰ āĻ•āĻžāĻ°ā§āĻĄ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_products_banner_title">āĻĒā§āϰ⧋āĻĄāĻžāĻ•ā§āϟ āĻĻ⧇āĻ–āĻžāϰ āĻŦā§āϝāĻžāύāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_products_banner_title">\'āĻĒāĻŖā§āϝ āĻĻ⧇āϖ⧁āύ\' āĻŦā§āϝāĻžāύāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_products_banner_summary_on">āĻŦā§āϝāĻžāύāĻžāϰ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_products_banner_summary_off">āĻŦā§āϝāĻžāύāĻžāϰ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_end_screen_store_banner_title">āĻļ⧇āώ āĻĒāĻ°ā§āĻĻāĻžāϰ āĻ¸ā§āĻŸā§‹āϰ āĻŦā§āϝāĻžāύāĻžāϰ āϞ⧁āĻ•āĻžāύ</string>
@@ -474,9 +430,9 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_disable_precise_seeking_gesture_summary_off">āĻ…āĻ™ā§āĻ—āĻ­āĻ™ā§āĻ—āĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
</patch>
<patch id="interaction.seekbar.enableSeekbarTappingPatch">
<string name="revanced_seekbar_tapping_title">āϏāĻŋāĻ•āĻŦāĻžāϰ⧇ āϚāĻžāĻĒ āĻĻ⧇āĻ“ā§ŸāĻž āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_seekbar_tapping_summary_on">āϏāĻŋāĻ•āĻŦāĻžāϰ⧇ āϚāĻžāĻĒ āĻĻ⧇āĻ“ā§ŸāĻž āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_seekbar_tapping_summary_off">āϏāĻŋāĻ•āĻŦāĻžāϰ⧇ āϚāĻžāĻĒ āĻĻ⧇āĻ“ā§ŸāĻž āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_seekbar_tapping_title">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ‚āĻļ⧇ āϝ⧇āϤ⧇ āĻŸā§āϝāĻžāĻĒ āĻ•āϰāĻž āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_seekbar_tapping_summary_on">āĻŸā§āϝāĻžāĻĒ āĻ•āϰ⧇ āĻ–ā§‹āρāϜāĻž āϏāĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_seekbar_tapping_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ‚āĻļ⧇ āϝ⧇āϤ⧇ āĻŸā§āϝāĻžāĻĒ āĻ•āϰāĻž āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
</patch>
<patch id="interaction.swipecontrols.swipeControlsResourcePatch">
<string name="revanced_swipe_brightness_title">āωāĻœā§āĻœā§āĻŦāϞāϤāĻžāϰ āϏ⧋āϝāĻŧāĻžāχāĻĒ āĻ…āĻ™ā§āĻ—āĻ­āĻ™ā§āĻ—āĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
@@ -489,9 +445,9 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
āĻ¸ā§āĻ•ā§āϰāĻŋāύ⧇āϰ āĻĄāĻžāύ āĻĻāĻŋāϕ⧇ āωāĻ˛ā§āϞāĻŽā§āĻŦāĻ­āĻžāĻŦ⧇ āϏ⧋āϝāĻŧāĻžāχāĻĒ āĻ•āϰ⧇ āĻ­āϞāĻŋāωāĻŽ āϏāĻžāĻŽāĻžā§āϜāĻ¸ā§āϝ āĻ•āϰ⧁āύ"</string>
<string name="revanced_swipe_volume_summary_off">āĻĒā§‚āĻ°ā§āĻŖ āĻ¸ā§āĻ•ā§āϰ⧀āύ āĻ­āϞāĻŋāωāĻŽ āϏ⧋āϝāĻŧāĻžāχāĻĒ āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_swipe_press_to_engage_title">āĻĒā§āϰ⧇āϏ-āϟ⧁-āĻ¸ā§‹ā§ŸāĻžāχāĻĒ āĻ…āĻ™ā§āĻ—āĻ­āĻ™ā§āĻ—āĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_swipe_press_to_engage_summary_on">āĻĒā§āϰ⧇āϏ-āϟ⧁-āĻ¸ā§‹ā§ŸāĻžāχāĻĒ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_swipe_press_to_engage_summary_off">āĻĒā§āϰ⧇āϏ-āϟ⧁-āĻ¸ā§‹ā§ŸāĻžāχāĻĒ āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_swipe_press_to_engage_title">āϏ⧋āϝāĻŧāĻžāχāĻĒ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰ⧇āϏ āĻ•āϰāĻž āĻ…āĻ™ā§āĻ—āĻ­āĻ™ā§āĻ—āĻŋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_swipe_press_to_engage_summary_on">āϏ⧋āϝāĻŧāĻžāχāĻĒ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰ⧇āϏ āĻ•āϰāĻž āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_swipe_press_to_engage_summary_off">āϏ⧋āϝāĻŧāĻžāχāĻĒ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰ⧇āϏ āĻ•āϰāĻž āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_swipe_haptic_feedback_title">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_swipe_haptic_feedback_summary_on">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_swipe_haptic_feedback_summary_off">āĻ•āĻŽā§āĻĒāύ āĻĒā§āϰāϤāĻŋāĻ•ā§āϰāĻŋāϝāĻŧāĻž āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
@@ -581,6 +537,9 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_subscriptions_button_title">āϏāĻĻāĻ¸ā§āϝāϤāĻž āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_subscriptions_button_summary_on">āϏāĻĻāĻ¸ā§āϝāϤāĻž āύāĻŋāύ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_subscriptions_button_summary_off">āϏāĻĻāĻ¸ā§āϝāϤāĻž āύāĻŋāύ āĻŦā§‹āϤāĻžāĻŽ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_notifications_button_title">āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_notifications_button_summary_on">āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋ āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇</string>
<string name="revanced_hide_notifications_button_summary_off">āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋ āĻŦā§‹āϤāĻžāĻŽ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšā§Ÿā§‡āϛ⧇</string>
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
<string name="revanced_switch_create_with_notifications_button_title">āϤ⧈āϰāĻŋ āĻŦā§‹āϤāĻžāĻŽāϕ⧇ āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋ āĻŦā§‹āϤāĻžāĻŽ āĻĻā§āĻŦāĻžāϰāĻž āϏ⧁āχāϚ āĻ•āϰ⧁āύ</string>
<string name="revanced_switch_create_with_notifications_button_summary_on">"āϤ⧈āϰāĻŋ āĻŦā§‹āϤāĻžāĻŽāϟāĻŋ āĻŦāĻŋāĻœā§āĻžāĻĒā§āϤāĻŋ āĻŦā§‹āϤāĻžāĻŽā§‡āϰ āϏāĻžāĻĨ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāĻž āĻšāϝāĻŧ
@@ -659,7 +618,7 @@ MicroG-āĻāϰ āϜāĻ¨ā§āϝ āĻŦā§āϝāĻžāϟāĻžāϰāĻŋ āĻ…āĻĒā§āϟāĻŋāĻŽāĻžāχāϜ
<string name="revanced_hide_player_flyout_video_quality_footer_summary_off">āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĢ⧁āϟāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāĻšā§āϛ⧇</string>
</patch>
<patch id="layout.buttons.overlay.hidePlayerOverlayButtonsPatch">
<string name="revanced_hide_player_previous_next_buttons_title">āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āϞ⧁āĻ•āĻžāύ &amp; āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻŦā§‹āϤāĻžāĻŽ</string>
<string name="revanced_hide_player_previous_next_buttons_title">āĻĒā§‚āĻ°ā§āĻŦāĻŦāĻ°ā§āϤ⧀ āϞ⧁āĻ•āĻžāύ &amp; āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻŦā§‹āϤāĻžāĻŽ</string>
<string name="revanced_hide_player_previous_next_buttons_summary_on">āĻŦā§‹āϤāĻžāĻŽ āϞ⧁āĻ•āĻžāύ⧋ āĻšāϝāĻŧ</string>
<string name="revanced_hide_player_previous_next_buttons_summary_off">āĻŦā§‹āϤāĻžāĻŽ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ</string>
<string name="revanced_hide_cast_button_title">āĻ•āĻžāĻ¸ā§āϟ āĻŦā§‹āϤāĻžāĻŽāϟāĻŋ āϞ⧁āĻ•āĻžāύ</string>
@@ -852,7 +811,6 @@ YouTube āϏ⧇āϟāĻŋāĻ‚āϏ⧇ āĻ…āĻŸā§‹ āĻĒā§āϞ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ
<string name="revanced_ryd_enable_summary_on">āĻ…āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞ⧋ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_ryd_enable_summary_off">āĻ…āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞ⧋ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§ŸāύāĻŋ</string>
<string name="revanced_ryd_shorts_title">Shorts āĻ āĻ…āĻĒāĻ›āĻ¨ā§āĻĻ āĻĻ⧇āĻ–āĻžāύ</string>
<string name="revanced_ryd_shorts_summary_on">Shorts-āĻ āĻ…āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞāĻŋ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_ryd_shorts_summary_on_disclaimer">"Shorts-āĻ āĻ…āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞāĻŋ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇
āϏ⧀āĻŽāĻžāĻŦāĻĻā§āϧāϤāĻž: āĻ›āĻĻā§āĻŽāĻŦ⧇āĻļā§€ āĻŽā§‹āĻĄā§‡ āĻ…āĻĒāĻ›āĻ¨ā§āĻĻāϗ⧁āϞāĻŋ āύāĻžāĻ“ āĻĻ⧇āĻ–āĻž āϝ⧇āϤ⧇ āĻĒāĻžāϰ⧇"</string>
@@ -1049,6 +1007,8 @@ YouTube āϏ⧇āϟāĻŋāĻ‚āϏ⧇ āĻ…āĻŸā§‹ āĻĒā§āϞ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ
<string name="revanced_sb_vote_downvote">āĻĄāĻžāωāύ āĻ­ā§‹āϟ</string>
<string name="revanced_sb_vote_category">āĻŦāĻŋāĻ­āĻžāĻ— āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
<string name="revanced_sb_vote_no_segments">āĻ­ā§‹āϟ āĻĻā§‡ā§ŸāĻžāϰ āϜāĻ¨ā§āϝ āφāϰ āϕ⧋āύ āϏ⧇āĻ—āĻŽā§‡āĻ¨ā§āϟ āύ⧇āχ</string>
<!-- A segment start and end time, such as "02:10 to 03:40" -->
<string name="revanced_sb_vote_segment_time_to_from">%1$s āĻĨ⧇āϕ⧇ %2$s</string>
<string name="revanced_sb_new_segment_choose_category">āϏ⧇āĻ—āĻŽā§‡āĻ¨ā§āĻŸā§‡āϰ āĻŦāĻŋāĻ­āĻžāĻ— āύāĻŋāĻ°ā§āĻŦāĻžāϚāύ āĻ•āϰ⧁āύ</string>
<string name="revanced_sb_new_segment_disabled_category">āϏ⧇āϟāĻŋāĻ‚ āĻĨ⧇āϕ⧇ āĻŦāĻŋāĻ­āĻžāĻ— āύāĻŋāĻ¸ā§āĻ•ā§āϰāĻŋ⧟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇āĨ¤ āϜāĻŽāĻž āĻĻāĻŋāϤ⧇ āĻŦāĻŋāĻ­āĻžāĻ— āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύāĨ¤</string>
<string name="revanced_sb_new_segment_title">āύāϤ⧁āύ āĻ¸ā§āĻĒāĻ¨ā§āϏāϰāĻŦā§āϞāĻ• āϏ⧇āĻ—āĻŽā§‡āĻ¨ā§āϟ</string>
@@ -1097,6 +1057,7 @@ YouTube āϏ⧇āϟāĻŋāĻ‚āϏ⧇ āĻ…āĻŸā§‹ āĻĒā§āϞ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ
<string name="revanced_sb_stats_saved_hour_format">%1$s āϘāĻ¨ā§āϟāĻž %2$s āĻŽāĻŋāύāĻŋāϟ</string>
<string name="revanced_sb_stats_saved_minute_format">%1$s āĻŽāĻŋāύāĻŋāϟ %2$s āϏ⧇āϕ⧇āĻ¨ā§āĻĄ</string>
<string name="revanced_sb_stats_saved_second_format">%s āϏ⧇āϕ⧇āĻ¨ā§āĻĄ</string>
<string name="revanced_sb_color_opacity_label">āĻ¸ā§āĻŦāĻšā§āĻ›āϤāĻž:</string>
<string name="revanced_sb_color_dot_label">āϰāĻ‚:</string>
<string name="revanced_sb_color_changed">āϰāĻ‚ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_sb_color_reset">āϰāĻ‚ āφāĻŦāĻžāϰ āϏ⧇āϟ āĻ•āϰ⧁āύ</string>
@@ -1112,16 +1073,14 @@ YouTube āϏ⧇āϟāĻŋāĻ‚āϏ⧇ āĻ…āĻŸā§‹ āĻĒā§āϞ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ
<string name="revanced_change_form_factor_entry_2">āĻĢā§‹āύ</string>
<string name="revanced_change_form_factor_entry_3">āĻŸā§āϝāĻžāĻŦāϞ⧇āϟ</string>
<string name="revanced_change_form_factor_entry_4">āĻ¸ā§āĻŦāϝāĻŧāĻ‚āϚāĻžāϞāĻŋāϤ</string>
<string name="revanced_change_form_factor_user_dialog_message">"āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞ⧋ āĻšāϞ:
<string name="revanced_change_form_factor_user_dialog_message">"āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞāĻŋāϰ āĻŽāĻ§ā§āϝ⧇ āϰāϝāĻŧ⧇āϛ⧇:
āĻŸā§āϝāĻžāĻŦāϞ⧇āϟ āϞ⧇āφāωāϟ
â€ĸ āĻ•āĻŽāĻŋāωāύāĻŋāϟāĻŋ āĻĒā§‹āĻ¸ā§āϟ āĻ—ā§‹āĻĒāύ
â€ĸ āĻ•āĻŽāĻŋāωāύāĻŋāϟāĻŋāϰ āĻĒā§‹āĻ¸ā§āϟāϗ⧁āϞāĻŋ āϞ⧁āĻ•āĻžāύ⧋ āφāϛ⧇
āĻ¸ā§āĻŦāϝāĻŧāĻ‚āϚāĻžāϞāĻŋāϤ āϞ⧇āφāωāϟ
â€ĸ āϘāĻĄāĻŧāĻŋāϰ āχāϤāĻŋāĻšāĻžāϏ āĻŽā§‡āύ⧁ āĻ—ā§‹āĻĒāύ
â€ĸ āĻāĻ•ā§āϏāĻĒā§āϞ⧋āϰ āĻŸā§āϝāĻžāĻŦ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇
â€ĸ āĻļāĻ°ā§āϟāϏ āύāĻŋāϝāĻŧāĻŽāĻŋāϤ āĻĒā§āϞ⧇āϝāĻŧāĻžāϰ⧇ āĻ–ā§‹āϞ⧇
â€ĸ āĻĢāĻŋāĻĄ āĻŦāĻŋāώāϝāĻŧ āĻāĻŦāĻ‚ āĻšā§āϝāĻžāύ⧇āϞ āĻĻā§āĻŦāĻžāϰāĻž āϏāĻ‚āĻ—āĻ āĻŋāϤ āĻšāϝāĻŧ"</string>
āĻ…āĻŸā§‹āĻŽā§‹āϟāĻŋāĻ­ āϞ⧇āφāωāϟ
â€ĸ Shorts āύāĻŋāϝāĻŧāĻŽāĻŋāϤ āĻĒā§āϞ⧇āϝāĻŧāĻžāϰ⧇ āĻ–ā§‹āϞ⧇
â€ĸ āĻĢāĻŋāĻĄ āĻŦāĻŋāώāϝāĻŧ āĻāĻŦāĻ‚ āĻšā§āϝāĻžāύ⧇āϞ āĻĻā§āĻŦāĻžāϰāĻž āϏāĻ‚āĻ—āĻ āĻŋāϤ"</string>
</patch>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<string name="revanced_spoof_app_version_title">āĻ…ā§āϝāĻžāĻĒ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
@@ -1136,12 +1095,7 @@ YouTube āϏ⧇āϟāĻŋāĻ‚āϏ⧇ āĻ…āĻŸā§‹ āĻĒā§āϞ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<string name="revanced_spoof_app_version_target_title">āĻ¸ā§āĻĒ⧁āĻĢ āĻ…ā§āϝāĻžāĻĒ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖ āϞāĻ•ā§āĻˇā§āϝ</string>
<string name="revanced_spoof_app_version_target_entry_1">19.35.36 - āĻĒ⧁āϰāύ⧋ Shorts āĻĒā§āϞ⧇āϝāĻŧāĻžāϰ āφāχāĻ•āύ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_app_version_target_entry_2">19.26.42 - āĻĒ⧁āϰāύ⧋ āύ⧇āĻ­āĻŋāϗ⧇āĻļāύ āφāχāĻ•āύ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧁āύ</string>
<!-- 'RYD' is 'Return YouTube Dislike' -->
<string name="revanced_spoof_app_version_target_legacy_entry_1">18.33.40 - āĻ›āĻĻā§āĻŽāĻŦ⧇āĻļāĻŋ āĻŽā§‹āĻĄā§‡ RYD āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧇</string>
<string name="revanced_spoof_app_version_target_legacy_entry_2">18.20.39 - āĻĒā§āϰāĻļā§āĻŦāĻ¸ā§āϤ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻ¸ā§āĻĒāĻŋāĻĄ āĻāĻŦāĻ‚ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧇</string>
<string name="revanced_spoof_app_version_target_legacy_entry_3">18.09.39 - āϞāĻžāχāĻŦā§āϰ⧇āϰāĻŋ āĻŸā§āϝāĻžāĻĒ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧇</string>
<string name="revanced_spoof_app_version_target_legacy_entry_4">17.33.42 - āĻĒ⧁āϰ⧋āύ⧋ āĻĒā§āϞ⧇āϞāĻŋāĻ¸ā§āϟ āĻļ⧇āϞāĻĢ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧇</string>
<string name="revanced_spoof_app_version_target_entry_2">19.01.34 - āĻĒ⧁āϰāύ⧋ āύ⧇āĻ­āĻŋāϗ⧇āĻļāύ āφāχāĻ•āύ āĻĒ⧁āύāϰ⧁āĻĻā§āϧāĻžāϰ āĻ•āϰ⧁āύ</string>
</patch>
<patch id="layout.startpage.changeStartPagePatch">
<string name="revanced_change_start_page_title">āĻļ⧁āϰ⧁āϰ āĻĒ⧃āĻˇā§āĻ āĻž āϏ⧇āϟ āĻ•āϰ⧁āύ</string>
@@ -1191,7 +1145,7 @@ YouTube āϏ⧇āϟāĻŋāĻ‚āϏ⧇ āĻ…āĻŸā§‹ āĻĒā§āϞ⧇ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ
</patch>
<patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">āĻŽāĻŋāύāĻŋāĻĒā§āĻ˛ā§‡ā§ŸāĻžāϰ</string>
<string name="revanced_miniplayer_screen_summary">āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻŽāĻ§ā§āϝāĻ•āĻžāϰ āĻŽāĻŋāύāĻŋāĻŽāĻžāχāϜāĻĄ āĻĒā§āĻ˛ā§‡ā§ŸāĻžāϰ āĻāϰ āϧāϰāĻŖ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
<string name="revanced_miniplayer_screen_summary">āχāύ-āĻ…ā§āϝāĻžāĻĒ āĻŽāĻŋāύāĻŋāĻŽāĻžāχāϜāĻĄ āĻĒā§āϞ⧇āϝāĻŧāĻžāϰ⧇āϰ āĻļ⧈āϞ⧀ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧁āύ</string>
<string name="revanced_miniplayer_type_title">āĻŽāĻŋāύāĻŋāĻĒā§āĻ˛ā§‡ā§ŸāĻžāϰ āϧāϰāĻŖ</string>
<string name="revanced_miniplayer_type_entry_0">āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋ⧟ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_miniplayer_type_entry_1">āĻĒā§‚āĻ°ā§āĻŦ-āύāĻŋāĻ°ā§āϧāĻžāϰāĻŋāϤ</string>
@@ -1244,8 +1198,6 @@ Miniplayer āĻ¸ā§āĻ•ā§āϰāĻŋāύ āĻĨ⧇āϕ⧇ āĻŦāĻžāĻŽā§‡ āĻŦāĻž āĻĄāĻžāύ⧇
<string name="revanced_gradient_loading_screen_title">āĻ—ā§āϰ⧇āĻĄāĻŋā§Ÿā§‡āĻ¨ā§āϟ āϞ⧋āĻĄāĻŋāĻ‚ āĻ¸ā§āĻ•ā§āϰāĻŋāĻŖ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_gradient_loading_screen_summary_on">āϞ⧋āĻĄāĻŋāĻ‚ āĻ¸ā§āĻ•ā§āϰāĻŋāϪ⧇ āĻāĻ•āϟāĻŋ āĻ—ā§āϰ⧇āĻĄāĻŋā§Ÿā§‡āĻ¨ā§āĻĄ āĻŦā§āϝāĻžāĻ•āĻ—ā§āϰāĻžāωāĻ¨ā§āĻĄ āĻĨāĻžāĻ•āĻŦ⧇</string>
<string name="revanced_gradient_loading_screen_summary_off">āϞ⧋āĻĄāĻŋāĻ‚ āĻ¸ā§āĻ•ā§āϰāĻŋāϪ⧇ āĻāĻ•āϟāĻŋ āϏāϞāĻŋāĻĄ āĻŦā§āϝāĻžāĻ•āĻ—ā§āϰāĻžāωāĻ¨ā§āĻĄ āĻĨāĻžāĻ•āĻŦ⧇</string>
</patch>
<patch id="layout.theme.themeResourcePatch">
<string name="revanced_seekbar_custom_color_title">āϏāĻŋāĻ•āĻŦāĻžāϰ⧇ āύāĻŋāϜāĻ¸ā§āĻŦ āϰāĻ‚ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_seekbar_custom_color_summary_on">āϏāĻŋāĻ•āĻŦāĻžāϰ⧇ āύāĻŋāϜāĻ¸ā§āĻŦ āϰāĻ‚ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_seekbar_custom_color_summary_off">āϏāĻŋāĻ•āĻŦāĻžāϰ⧇ āĻŽā§‚āϞ āϰāĻ‚ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
@@ -1337,8 +1289,8 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
</patch>
<patch id="misc.links.openLinksExternallyPatch">
<string name="revanced_external_browser_title">āϞāĻŋāĻ‚āĻ• āĻŦā§āϰāĻžāωāϜāĻžāϰ⧇ āϖ⧁āϞ⧁āύ</string>
<string name="revanced_external_browser_summary_on">āϞāĻŋāĻ‚āĻ• āĻŦāĻžāĻšāĻŋāϰ⧇ āϖ⧁āϞ⧁āύ</string>
<string name="revanced_external_browser_summary_off">āĻ…ā§āϝāĻžāĻĒ⧇āϰ āĻŽāĻ§ā§āϝ⧇ āϞāĻŋāĻ‚āĻ• āϖ⧁āϞāϛ⧇</string>
<string name="revanced_external_browser_summary_on">āĻŦāĻžāĻšā§āϝāĻŋāĻ• āĻŦā§āϰāĻžāωāϜāĻžāϰ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ–ā§‹āϞāĻž āĻšāĻšā§āϛ⧇</string>
<string name="revanced_external_browser_summary_off">āχāύ-āĻ…ā§āϝāĻžāĻĒ āĻŦā§āϰāĻžāωāϜāĻžāϰ⧇ āϞāĻŋāĻ™ā§āĻ• āĻ–ā§‹āϞāĻž āĻšāĻšā§āϛ⧇</string>
</patch>
<patch id="misc.privacy.removeTrackingQueryParameterPatch">
<string name="revanced_remove_tracking_query_parameter_title">āĻŸā§āĻ°ā§āϝāĻžāĻ•āĻŋāĻ‚ āĻ•āϰāĻžāϰ āĻĒā§āϝāĻžāϰāĻžāĻŽāĻŋāϟāĻžāϰ āĻŽā§āϛ⧁āύ</string>
@@ -1365,9 +1317,15 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
<string name="revanced_remember_video_quality_last_selected_summary_off">āϗ⧁āĻŖāĻŽāĻžāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻŦāĻ°ā§āϤāĻŽāĻžāύ āĻ­āĻŋāĻĄāĻŋāĻ“āϤ⧇ āĻĒā§āĻ°ā§Ÿā§‹āĻ— āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_video_quality_default_wifi_title">āĻ“ā§ŸāĻžāχ-āĻĢāĻžāχ āύ⧇āϟāĻ“ā§ŸāĻžāĻ°ā§āϕ⧇ āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ</string>
<string name="revanced_video_quality_default_mobile_title">āĻŽā§‹āĻŦāĻžāχāϞ āύ⧇āϟāĻ“ā§ŸāĻžāĻ°ā§āϕ⧇ āĻĄāĻŋāĻĢāĻ˛ā§āϟ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ</string>
<string name="revanced_remember_shorts_quality_last_selected_title">Shorts āϗ⧁āĻŖāĻŽāĻžāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ⧇āϰ āĻ•āĻĨāĻž āĻŽāύ⧇ āϰāĻžāϖ⧁āύ</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_on">āϗ⧁āĻŖāĻŽāĻžāύ⧇āϰ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞāĻŋ āϏāĻŽāĻ¸ā§āϤ Shorts-āĻāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāϝ⧋āĻœā§āϝ</string>
<string name="revanced_remember_shorts_quality_last_selected_summary_off">āϗ⧁āĻŖāĻŽāĻžāύ⧇āϰ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύāϗ⧁āϞāĻŋ āĻļ⧁āϧ⧁āĻŽāĻžāĻ¤ā§āϰ āĻŦāĻ°ā§āϤāĻŽāĻžāύ Short-āĻāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāϝ⧋āĻœā§āϝ</string>
<string name="revanced_shorts_quality_default_wifi_title">Wi-Fi āύ⧇āϟāĻ“āϝāĻŧāĻžāĻ°ā§āϕ⧇ āĻĄāĻŋāĻĢāĻ˛ā§āϟ Shorts āϗ⧁āĻŖāĻŽāĻžāύ</string>
<string name="revanced_shorts_quality_default_mobile_title">āĻŽā§‹āĻŦāĻžāχāϞ āύ⧇āϟāĻ“āϝāĻŧāĻžāĻ°ā§āϕ⧇ āĻĄāĻŋāĻĢāĻ˛ā§āϟ Shorts āϗ⧁āĻŖāĻŽāĻžāύ</string>
<string name="revanced_remember_video_quality_mobile">āĻŽā§‹āĻŦāĻžāχāϞ</string>
<string name="revanced_remember_video_quality_wifi">āĻ“ā§ŸāĻžāχ-āĻĢāĻžāχ</string>
<string name="revanced_remember_video_quality_toast">āĻĄāĻŋāĻĢāĻ˛ā§āϟ %1$s āϗ⧁āĻŖāĻŽāĻžāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻšāĻšā§āϛ⧇: %2$s</string>
<string name="revanced_remember_video_quality_toast_shorts">Shorts %1$s āĻāϰ āϗ⧁āĻŖāĻŽāĻžāύ āĻĒāϰāĻŋāĻŦāĻ°ā§āϤāύ āĻ•āϰ⧇: %2$s</string>
</patch>
<patch id="video.speed.button.playbackSpeedButtonPatch">
<string name="revanced_playback_speed_dialog_button_title">āĻ¸ā§āĻĒāĻŋāĻĄ āĻĄāĻžā§ŸāĻžāϞāĻ— āĻŦā§‹āϤāĻžāĻŽ āĻĻ⧇āĻ–āĻžāύ</string>
@@ -1398,10 +1356,10 @@ DeArrow āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇ āφāϰāĻ“ āϜāĻžāύāϤ⧇ āĻāĻ–āĻžāύ⧇ āϟ
<string name="revanced_disable_hdr_video_summary_on">HDR āĻ­āĻŋāĻĄāĻŋāĻ“ āύāĻŋāĻˇā§āĻ•ā§āϰāĻŋāϝāĻŧ āĻ•āϰāĻž āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_disable_hdr_video_summary_off">HDR āĻ­āĻŋāĻĄāĻŋāĻ“ āϏāĻ•ā§āϰāĻŋ⧟ āĻšāϝāĻŧ⧇āϛ⧇</string>
</patch>
<patch id="video.videoqualitymenu.restoreOldVideoQualityMenuResourcePatch">
<string name="revanced_restore_old_video_quality_menu_title">āĻĒ⧁āϰ⧋āύ⧋ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āωāĻĻā§āϧāĻžāϰ āĻ•āϰ⧁āύ</string>
<string name="revanced_restore_old_video_quality_menu_summary_on">āĻĒ⧁āϰ⧋āύ⧋ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_restore_old_video_quality_menu_summary_off">āĻĒ⧁āϰ⧋āύ⧋ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§ŸāύāĻŋ</string>
<patch id="video.quality.advancedVideoQualityMenuPatch">
<string name="revanced_advanced_video_quality_menu_title">āωāĻ¨ā§āύāϤ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĻ⧇āĻ–āĻžāύ</string>
<string name="revanced_advanced_video_quality_menu_summary_on">āωāĻ¨ā§āύāϤ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧ⧇āϛ⧇</string>
<string name="revanced_advanced_video_quality_menu_summary_off">āωāĻ¨ā§āύāϤ āĻ­āĻŋāĻĄāĻŋāĻ“ āϗ⧁āĻŖāĻŽāĻžāύ āĻŽā§‡āύ⧁ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāϝāĻŧāύāĻŋ</string>
</patch>
<patch id="interaction.seekbar.enableSlideToSeekPatch">
<string name="revanced_slide_to_seek_title">āĻ­āĻŋāĻĄāĻŋāĻ“āϰ āύāĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āϟ āĻ…āĻ‚āĻļ⧇ āϝ⧇āϤ⧇ āϟāĻžāύ⧁āύ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>

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