Compare commits

...

82 Commits

Author SHA1 Message Date
semantic-release-bot
b5b6ef5d6f chore(release): 4.14.0-dev.15 [skip ci]
# [4.14.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.14...v4.14.0-dev.15) (2024-09-17)

### Bug Fixes

* **YouTube:** Fix issues related to playback by replace streaming data ([#3582](https://github.com/ReVanced/revanced-patches/issues/3582)) ([5b1e07d](5b1e07d861))
2024-09-17 22:47:28 +00:00
Zain
5b1e07d861 fix(YouTube): Fix issues related to playback by replace streaming data (#3582)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-09-18 00:45:02 +02:00
ReVanced Bot
e3220cc10a chore: Sync translations (#3649) 2024-09-17 12:37:00 -04:00
semantic-release-bot
02db9378ea chore(release): 4.14.0-dev.14 [skip ci]
# [4.14.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.13...v4.14.0-dev.14) (2024-09-17)

### Features

* **YouTube Music:** Make working patches compatible with latest versions ([#3556](https://github.com/ReVanced/revanced-patches/issues/3556)) ([f83e314](f83e314dff))
2024-09-17 13:58:02 +00:00
Pun Butrach
f83e314dff feat(YouTube Music): Make working patches compatible with latest versions (#3556) 2024-09-17 15:56:00 +02:00
semantic-release-bot
d5e383b78a chore(release): 4.14.0-dev.13 [skip ci]
# [4.14.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.12...v4.14.0-dev.13) (2024-09-17)

### Features

* **YouTube - Hide Shorts components:** Hide 'Use this sound' button ([#3647](https://github.com/ReVanced/revanced-patches/issues/3647)) ([395e18d](395e18d830))
2024-09-17 13:36:53 +00:00
MarcaD
395e18d830 feat(YouTube - Hide Shorts components): Hide 'Use this sound' button (#3647) 2024-09-17 15:34:31 +02:00
semantic-release-bot
887684e7c7 chore(release): 4.14.0-dev.12 [skip ci]
# [4.14.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.11...v4.14.0-dev.12) (2024-09-14)

### Bug Fixes

* **Soundcloud - Hide ads:** Support latest version ([#3628](https://github.com/ReVanced/revanced-patches/issues/3628)) ([2f7d751](2f7d751f9f))
2024-09-14 15:09:54 +00:00
FullerBread2032
2f7d751f9f fix(Soundcloud - Hide ads): Support latest version (#3628)
Co-authored-by: FullerBread2032 <admin@fullerbread2032.tk>
2024-09-14 17:07:27 +02:00
semantic-release-bot
4886a95713 chore(release): 4.14.0-dev.11 [skip ci]
# [4.14.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.10...v4.14.0-dev.11) (2024-09-12)

### Features

* **Sync for Reddit:** Rename patch to `Use /user/ endpoint` ([5871923](58719239cf))
2024-09-12 20:11:21 +00:00
oSumAtrIX
58719239cf feat(Sync for Reddit): Rename patch to Use /user/ endpoint
The bug it was used to fix does not occur anymore. This name is more correct on what the patch actually does.
2024-09-12 22:09:09 +02:00
semantic-release-bot
fcb68cc65e chore(release): 4.14.0-dev.10 [skip ci]
# [4.14.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.9...v4.14.0-dev.10) (2024-09-12)

### Features

* **Sync for Reddit:** Add `Fix /user/ endpoint` patch ([16217f0](16217f012e))
2024-09-12 18:30:19 +00:00
oSumAtrIX
16217f012e feat(Sync for Reddit): Add Fix /user/ endpoint patch 2024-09-12 20:18:22 +02:00
semantic-release-bot
d6f20ee67d chore(release): 4.14.0-dev.9 [skip ci]
# [4.14.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.8...v4.14.0-dev.9) (2024-09-09)

### Features

* **YouTube:** Add donation link to settings about screen ([#3626](https://github.com/ReVanced/revanced-patches/issues/3626)) ([bccd62e](bccd62e593))
2024-09-09 07:23:22 +00:00
LisoUseInAIKyrios
bccd62e593 feat(YouTube): Add donation link to settings about screen (#3626) 2024-09-09 03:21:22 -04:00
semantic-release-bot
1322403698 chore(release): 4.14.0-dev.8 [skip ci]
# [4.14.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.7...v4.14.0-dev.8) (2024-09-09)

### Bug Fixes

* **YouTube - SponsorBlock:** Add summary text to 'view my segments' button ([a642705](a64270514f))
2024-09-09 07:19:55 +00:00
LisoUseInAIKyrios
a64270514f fix(YouTube - SponsorBlock): Add summary text to 'view my segments' button 2024-09-09 03:17:43 -04:00
semantic-release-bot
f5de555adf chore(release): 4.14.0-dev.7 [skip ci]
# [4.14.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.6...v4.14.0-dev.7) (2024-09-06)

### Features

* Add `Check environment` patch ([#3610](https://github.com/ReVanced/revanced-patches/issues/3610)) ([4c2ec28](4c2ec2870c))
2024-09-06 08:29:07 +00:00
oSumAtrIX
4c2ec2870c feat: Add Check environment patch (#3610)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: KobeW50 <84587632+KobeW50@users.noreply.github.com>
2024-09-06 10:26:53 +02:00
semantic-release-bot
a73e2458e9 chore(release): 4.14.0-dev.6 [skip ci]
# [4.14.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.5...v4.14.0-dev.6) (2024-09-06)

### Features

* Add `Change data directory location` patch ([#3602](https://github.com/ReVanced/revanced-patches/issues/3602)) ([96e6f43](96e6f43ca0))
2024-09-06 07:47:45 +00:00
KrystianQur
96e6f43ca0 feat: Add Change data directory location patch (#3602)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-09-06 09:45:40 +02:00
semantic-release-bot
f667d5a238 chore(release): 4.14.0-dev.5 [skip ci]
# [4.14.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.4...v4.14.0-dev.5) (2024-09-06)

### Bug Fixes

* **Pixiv - Hide ads:** Fix for latest version ([#3616](https://github.com/ReVanced/revanced-patches/issues/3616)) ([ff2c456](ff2c4564a0))
2024-09-06 07:16:05 +00:00
Itroublve
ff2c4564a0 fix(Pixiv - Hide ads): Fix for latest version (#3616)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-09-06 09:13:57 +02:00
semantic-release-bot
b568207e49 chore(release): 4.14.0-dev.4 [skip ci]
# [4.14.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.3...v4.14.0-dev.4) (2024-09-01)

### Bug Fixes

* **YouTube - ReturnYouTubeDislike:** Show estimated like count for videos with hidden likes ([#3601](https://github.com/ReVanced/revanced-patches/issues/3601)) ([70470a9](70470a9162))
2024-09-01 21:51:42 +00:00
LisoUseInAIKyrios
70470a9162 fix(YouTube - ReturnYouTubeDislike): Show estimated like count for videos with hidden likes (#3601) 2024-09-01 17:49:42 -04:00
semantic-release-bot
9922f47a49 chore(release): 4.14.0-dev.3 [skip ci]
# [4.14.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.2...v4.14.0-dev.3) (2024-08-30)

### Features

* **YouTube - Keyword filter:** Add syntax to match whole keywords and not substrings ([#3592](https://github.com/ReVanced/revanced-patches/issues/3592)) ([ed532eb](ed532eb528))
2024-08-30 21:40:57 +00:00
LisoUseInAIKyrios
ed532eb528 feat(YouTube - Keyword filter): Add syntax to match whole keywords and not substrings (#3592) 2024-08-30 17:38:59 -04:00
ReVanced Bot
74f3f82927 chore: Sync translations (#3593) 2024-08-28 22:33:49 -04:00
semantic-release-bot
6544cd5fc6 chore(release): 4.14.0-dev.2 [skip ci]
# [4.14.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.1...v4.14.0-dev.2) (2024-08-24)

### Features

* **Duolingo:** Add `Disable ads` and `Enable debug menu` patch ([#3422](https://github.com/ReVanced/revanced-patches/issues/3422)) ([4e323aa](4e323aa206))
2024-08-24 12:46:50 +00:00
Joshua May
4e323aa206 feat(Duolingo): Add Disable ads and Enable debug menu patch (#3422)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2024-08-24 14:44:35 +02:00
ReVanced Bot
c1cee281ff chore: Sync translations (#3574) 2024-08-23 00:37:22 -04:00
ReVanced Bot
0779f9fc5e chore: Sync translations (#3573) 2024-08-23 00:13:52 -04:00
semantic-release-bot
0ee5cf98ab chore(release): 4.14.0-dev.1 [skip ci]
# [4.14.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.4-dev.2...v4.14.0-dev.1) (2024-08-22)

### Features

* **YouTube - Spoof client:** Allow forcing AVC codec with iOS ([#3570](https://github.com/ReVanced/revanced-patches/issues/3570)) ([6bb848b](6bb848b991))
2024-08-22 17:51:00 +00:00
LisoUseInAIKyrios
6bb848b991 feat(YouTube - Spoof client): Allow forcing AVC codec with iOS (#3570) 2024-08-22 13:48:49 -04:00
semantic-release-bot
188b66ffe7 chore(release): 4.13.4-dev.2 [skip ci]
## [4.13.4-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.13.4-dev.1...v4.13.4-dev.2) (2024-08-20)

### Bug Fixes

* **YouTube - SponsorBlock:** Handle if the user enters an invalid number into any SB settings ([a276425](a276425d83))
2024-08-20 04:19:14 +00:00
LisoUseInAIKyrios
a276425d83 fix(YouTube - SponsorBlock): Handle if the user enters an invalid number into any SB settings 2024-08-20 00:17:11 -04:00
LisoUseInAIKyrios
e556c3f692 chore: Sync translations (#3564) 2024-08-20 00:16:08 -04:00
revanced-bot
cb30248eab chore: Sync translations 2024-08-20 04:15:01 +00:00
semantic-release-bot
c5ce742ab4 chore(release): 4.13.4-dev.1 [skip ci]
## [4.13.4-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.3...v4.13.4-dev.1) (2024-08-18)

### Bug Fixes

* **SwissID:** Rename `Remove Google Play Integrity Integrity check` to `Remove Google Play Integrity check` ([#3558](https://github.com/ReVanced/revanced-patches/issues/3558)) ([bdd2f7c](bdd2f7cb0f))
2024-08-18 13:22:20 +00:00
Pun Butrach
bdd2f7cb0f fix(SwissID): Rename Remove Google Play Integrity Integrity check to Remove Google Play Integrity check (#3558) 2024-08-18 17:20:23 +04:00
semantic-release-bot
b7600f448d chore(release): 4.13.3 [skip ci]
## [4.13.3](https://github.com/ReVanced/revanced-patches/compare/v4.13.2...v4.13.3) (2024-08-15)

### Bug Fixes

* **YouTube:** Remove translated string that breaks patching ([aa3487a](aa3487aa92))
2024-08-15 20:40:18 +00:00
LisoUseInAIKyrios
5c4bf7676d chore: Merge branch dev to main (#3552) 2024-08-15 16:38:21 -04:00
semantic-release-bot
fcd2f9b4c4 chore(release): 4.13.3-dev.1 [skip ci]
## [4.13.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.2...v4.13.3-dev.1) (2024-08-15)

### Bug Fixes

* **YouTube:** Remove translated string that breaks patching ([aa3487a](aa3487aa92))
2024-08-15 20:36:50 +00:00
LisoUseInAIKyrios
aa3487aa92 fix(YouTube): Remove translated string that breaks patching 2024-08-15 16:34:52 -04:00
LisoUseInAIKyrios
ada642f4a7 chore: Merge branch dev to main (#3551) 2024-08-15 16:29:00 -04:00
LisoUseInAIKyrios
eac758588a chore: Remove non breaking space from German translation 2024-08-15 16:14:36 -04:00
ReVanced Bot
5d047eae77 chore: Sync translations (#3550) 2024-08-15 15:58:52 -04:00
semantic-release-bot
ed92bf1be6 chore(release): 4.13.2 [skip ci]
## [4.13.2](https://github.com/ReVanced/revanced-patches/compare/v4.13.1...v4.13.2) (2024-08-15)

### Bug Fixes

* **YouTube - GmsCore Support:** Fix patch exception by using correct patch offset ([#3543](https://github.com/ReVanced/revanced-patches/issues/3543)) ([3d0d94b](3d0d94b6c8))
2024-08-15 18:39:08 +00:00
oSumAtrIX
c6318e890f chore: Merge branch dev to main (#3544) 2024-08-15 22:37:04 +04:00
semantic-release-bot
7f3b1c54da chore(release): 4.13.2-dev.1 [skip ci]
## [4.13.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.1...v4.13.2-dev.1) (2024-08-15)

### Bug Fixes

* **YouTube - GmsCore Support:** Fix patch exception by using correct patch offset ([#3543](https://github.com/ReVanced/revanced-patches/issues/3543)) ([3d0d94b](3d0d94b6c8))
2024-08-15 18:35:56 +00:00
LisoUseInAIKyrios
3d0d94b6c8 fix(YouTube - GmsCore Support): Fix patch exception by using correct patch offset (#3543) 2024-08-15 22:33:53 +04:00
semantic-release-bot
b84e6afebd chore(release): 4.13.1 [skip ci]
## [4.13.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.0...v4.13.1) (2024-08-15)

### Bug Fixes

* **YouTube - Check watch history domain name resolution:** Add compatibility field ([d7be94a](d7be94a193))
2024-08-15 17:58:11 +00:00
oSumAtrIX
3eab130276 chore: Merge branch dev to main (#3541) 2024-08-15 21:55:53 +04:00
semantic-release-bot
95f8e9b3a9 chore(release): 4.13.1-dev.1 [skip ci]
## [4.13.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.0...v4.13.1-dev.1) (2024-08-15)

### Bug Fixes

* **YouTube - Check watch history domain name resolution:** Add compatibility field ([d7be94a](d7be94a193))
2024-08-15 17:53:15 +00:00
LisoUseInAIKyrios
d7be94a193 fix(YouTube - Check watch history domain name resolution): Add compatibility field 2024-08-15 13:51:02 -04:00
semantic-release-bot
e4e20bec6c chore(release): 4.13.0 [skip ci]
# [4.13.0](https://github.com/ReVanced/revanced-patches/compare/v4.12.0...v4.13.0) (2024-08-15)

### Bug Fixes

* **YouTube - GmsCore support:** Fix notifications not working by using the correct permissions ([c64757f](c64757f80a))

### Features

* **Google Photos:** Add `Spoof features` patch ([#3459](https://github.com/ReVanced/revanced-patches/issues/3459)) ([f814d87](f814d87c17))
* **SCB Easy:** Remove broken `Remove debugging detection` patch ([#3518](https://github.com/ReVanced/revanced-patches/issues/3518)) ([45e4f70](45e4f70137))
* **YouTube:** Add `Check watch history domain name resolution` patch ([#3537](https://github.com/ReVanced/revanced-patches/issues/3537)) ([87eb836](87eb83607c))
2024-08-15 17:29:30 +00:00
oSumAtrIX
b8bd63a34c chore: Merge branch dev to main (#3533) 2024-08-15 21:26:59 +04:00
semantic-release-bot
8b602ca6be chore(release): 4.13.0-dev.2 [skip ci]
# [4.13.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.13.0-dev.1...v4.13.0-dev.2) (2024-08-15)

### Features

* **YouTube:** Add `Check watch history domain name resolution` patch ([#3537](https://github.com/ReVanced/revanced-patches/issues/3537)) ([87eb836](87eb83607c))
2024-08-15 16:08:55 +00:00
LisoUseInAIKyrios
87eb83607c feat(YouTube): Add Check watch history domain name resolution patch (#3537)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-08-15 12:06:19 -04:00
semantic-release-bot
567121d641 chore(release): 4.13.0-dev.1 [skip ci]
# [4.13.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.12.1-dev.1...v4.13.0-dev.1) (2024-08-15)

### Features

* **Google Photos:** Add `Spoof features` patch ([#3459](https://github.com/ReVanced/revanced-patches/issues/3459)) ([f814d87](f814d87c17))
* **SCB Easy:** Remove broken `Remove debugging detection` patch ([#3518](https://github.com/ReVanced/revanced-patches/issues/3518)) ([45e4f70](45e4f70137))
2024-08-15 05:47:21 +00:00
Pun Butrach
45e4f70137 feat(SCB Easy): Remove broken Remove debugging detection patch (#3518)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-08-15 07:45:00 +02:00
oSumAtrIX
f814d87c17 feat(Google Photos): Add Spoof features patch (#3459) 2024-08-15 07:43:01 +02:00
semantic-release-bot
d0e92b225e chore(release): 4.12.1-dev.1 [skip ci]
## [4.12.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.12.0...v4.12.1-dev.1) (2024-08-15)

### Bug Fixes

* **YouTube - GmsCore support:** Fix notifications not working by using the correct permissions ([c64757f](c64757f80a))
2024-08-15 05:41:06 +00:00
oSumAtrIX
c64757f80a fix(YouTube - GmsCore support): Fix notifications not working by using the correct permissions
Regression had been introduced in 1af65de1f6. This commit reverts this.
2024-08-15 07:39:00 +02:00
ReVanced Bot
58b6f1fba0 chore: Sync translations (#3532) 2024-08-13 01:13:23 -04:00
semantic-release-bot
630857ba16 chore(release): 4.12.0 [skip ci]
# [4.12.0](https://github.com/ReVanced/revanced-patches/compare/v4.11.0...v4.12.0) (2024-08-06)

### Bug Fixes

* **Google Photos - GmsCore support:** Fix by checking first if a method exists before trying to patch it ([26449cf](26449cf7c6))
* **Instagram - Hide ads:**  Restore compatibility with latest version by fixing fingerprint ([#3455](https://github.com/ReVanced/revanced-patches/issues/3455)) ([f2bf2da](f2bf2da9a5))
* **Messenger - Disable switching emoji to sticker:** Constrain to last working version `439.0.0.29.119` ([1cf25f9](1cf25f9dc9))
* **SoundCloud - Enable offline sync:** Stop crashing by reversing order of patching instructions from last to first to retain indices ([98f9bba](98f9bba7ed))
* **YouTube - Bypass image region restrictions:** Move setting to `Misc` menu ([7acb6cd](7acb6cdc96))
* **YouTube - Client Spoof:** Restore missing high qualities by spoofing the iOS client user agent ([#3468](https://github.com/ReVanced/revanced-patches/issues/3468)) ([a4b0e76](a4b0e76755))
* **YouTube - Hide keyword content:** Do not hide flyout menu ([cfbc4aa](cfbc4aa6b2))
* **YouTube - SponsorBlock:** Correctly show minute timestamp when creating a new segment ([8886fc4](8886fc4f54))
* **YouTube - SponsorBlock:** Improve create segment manual seek accuracy ([#3491](https://github.com/ReVanced/revanced-patches/issues/3491)) ([2e8d5c6](2e8d5c61f8))
* **YouTube - Spoof client:** Fix tracking history on brand accounts ([#3480](https://github.com/ReVanced/revanced-patches/issues/3480)) ([eed856d](eed856d64c))
* **YouTube - Spoof client:** Restore livestream audio only playback with iOS spoofing ([#3504](https://github.com/ReVanced/revanced-patches/issues/3504)) ([eadbf5f](eadbf5f459))

### Features

* Add `Hide mock location` patch ([#3417](https://github.com/ReVanced/revanced-patches/issues/3417)) ([250cc7c](250cc7cbde))
* Add `Spoof build info` patch ([d87f36e](d87f36e7e2))
* **Boost for Reddit:** Add `Disable ads` patch ([#3474](https://github.com/ReVanced/revanced-patches/issues/3474)) ([d2afc53](d2afc53c2b))
* **CandyLink:** Remove non-functional `Unlock pro` patch ([1e81d0c](1e81d0c9f8))
* **Expense Manager:** Remove non-functional `Unlock pro` patch ([e4232b6](e4232b6c74))
* **Google News:** Add `Enable CustomTabs` and `GmsCore support` patch ([#3111](https://github.com/ReVanced/revanced-patches/issues/3111)) ([273af26](273af26274))
* **Google Photos:** Add `GmsCore support` patch ([#3414](https://github.com/ReVanced/revanced-patches/issues/3414)) ([1af65de](1af65de1f6))
* **Instagram:** Remove unnecessary `Hide timeline ads` patch ([8038bd2](8038bd2e98))
* **SoundCloud:** Add `Enable offline sync` patch ([#3407](https://github.com/ReVanced/revanced-patches/issues/3407)) ([b944fb7](b944fb7bf1))
* **SwissID:** Add `Remove Google Play Integrity Integrity check` patch ([#3478](https://github.com/ReVanced/revanced-patches/issues/3478)) ([3380080](33800801a3))
* **YouTube - Description components:** Add `Hide 'Key concepts' section` option ([#3495](https://github.com/ReVanced/revanced-patches/issues/3495)) ([337bdc3](337bdc3d39))
* **YouTube:** Add `Bypass image region restrictions` patch ([#3442](https://github.com/ReVanced/revanced-patches/issues/3442)) ([9ef51ab](9ef51abde7))
2024-08-06 00:08:03 +00:00
oSumAtrIX
82ae367946 chore: Merge branch dev to main (#3438) 2024-08-06 02:05:44 +02:00
semantic-release-bot
95a7118dcf chore(release): 4.12.0-dev.17 [skip ci]
# [4.12.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.16...v4.12.0-dev.17) (2024-08-06)

### Bug Fixes

* **Google Photos - GmsCore support:** Fix by checking first if a method exists before trying to patch it ([26449cf](26449cf7c6))
* **Messenger - Disable switching emoji to sticker:** Constrain to last working version `439.0.0.29.119` ([1cf25f9](1cf25f9dc9))

### Features

* **CandyLink:** Remove non-functional `Unlock pro` patch ([1e81d0c](1e81d0c9f8))
* **Expense Manager:** Remove non-functional `Unlock pro` patch ([e4232b6](e4232b6c74))
* **Instagram:** Remove unnecessary `Hide timeline ads` patch ([8038bd2](8038bd2e98))
2024-08-06 00:04:26 +00:00
oSumAtrIX
26449cf7c6 fix(Google Photos - GmsCore support): Fix by checking first if a method exists before trying to patch it 2024-08-06 02:01:44 +02:00
oSumAtrIX
e4232b6c74 feat(Expense Manager): Remove non-functional Unlock pro patch 2024-08-06 01:40:11 +02:00
oSumAtrIX
1cf25f9dc9 fix(Messenger - Disable switching emoji to sticker): Constrain to last working version 439.0.0.29.119 2024-08-06 01:31:46 +02:00
oSumAtrIX
8038bd2e98 feat(Instagram): Remove unnecessary Hide timeline ads patch
The `Hide ads` patch supersedes this patch.
2024-08-06 01:27:06 +02:00
oSumAtrIX
1e81d0c9f8 feat(CandyLink): Remove non-functional Unlock pro patch
Servers now check the purchase status.
2024-08-06 01:25:28 +02:00
ReVanced Bot
c48cedaddf chore: Sync translations (#3507) 2024-08-05 15:56:44 -04:00
semantic-release-bot
4085d1f9dc chore(release): 4.12.0-dev.16 [skip ci]
# [4.12.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.15...v4.12.0-dev.16) (2024-08-04)

### Bug Fixes

* **YouTube - Spoof client:** Restore livestream audio only playback with iOS spoofing ([#3504](https://github.com/ReVanced/revanced-patches/issues/3504)) ([eadbf5f](eadbf5f459))
2024-08-04 19:40:12 +00:00
LisoUseInAIKyrios
eadbf5f459 fix(YouTube - Spoof client): Restore livestream audio only playback with iOS spoofing (#3504) 2024-08-04 21:38:10 +02:00
ILoveOpenSourceApplications
b12b3a73a6 refactor(YouTube Music): Rename Hide music video ads to Hide video ads and add patch description (#3494)
Co-authored-by: ILoveOpenSourceApplications <ILoveOpenSourceApplications@users.noreply.github.com>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2024-08-04 10:09:48 +02:00
semantic-release-bot
572a310589 chore(release): 4.12.0-dev.15 [skip ci]
# [4.12.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.14...v4.12.0-dev.15) (2024-08-02)

### Bug Fixes

* **YouTube - SponsorBlock:** Improve create segment manual seek accuracy ([#3491](https://github.com/ReVanced/revanced-patches/issues/3491)) ([2e8d5c6](2e8d5c61f8))
2024-08-02 13:42:52 +00:00
LisoUseInAIKyrios
2e8d5c61f8 fix(YouTube - SponsorBlock): Improve create segment manual seek accuracy (#3491) 2024-08-02 09:40:28 -04:00
ReVanced Bot
025766bb42 chore: Sync translations (#3499) 2024-08-02 09:37:23 -04:00
semantic-release-bot
e31966159a chore(release): 4.12.0-dev.14 [skip ci]
# [4.12.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.13...v4.12.0-dev.14) (2024-08-01)

### Features

* **YouTube - Description components:** Add `Hide 'Key concepts' section` option ([#3495](https://github.com/ReVanced/revanced-patches/issues/3495)) ([337bdc3](337bdc3d39))
2024-08-01 11:29:29 +00:00
ILoveOpenSourceApplications
337bdc3d39 feat(YouTube - Description components): Add Hide 'Key concepts' section option (#3495)
Co-authored-by: ILoveOpenSourceApplications <ILoveOpenSourceApplications@users.noreply.github.com>
2024-08-01 13:27:28 +02:00
177 changed files with 7758 additions and 6256 deletions

View File

@@ -1,3 +1,269 @@
# [4.14.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.14...v4.14.0-dev.15) (2024-09-17)
### Bug Fixes
* **YouTube:** Fix issues related to playback by replace streaming data ([#3582](https://github.com/ReVanced/revanced-patches/issues/3582)) ([dfa94d7](https://github.com/ReVanced/revanced-patches/commit/dfa94d70f65150d6ef24ea6378b8e6a317055186))
# [4.14.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.13...v4.14.0-dev.14) (2024-09-17)
### Features
* **YouTube Music:** Make working patches compatible with latest versions ([#3556](https://github.com/ReVanced/revanced-patches/issues/3556)) ([12f6f19](https://github.com/ReVanced/revanced-patches/commit/12f6f1966ad04631451940f7b64d785c3ef481a0))
# [4.14.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.12...v4.14.0-dev.13) (2024-09-17)
### Features
* **YouTube - Hide Shorts components:** Hide 'Use this sound' button ([#3647](https://github.com/ReVanced/revanced-patches/issues/3647)) ([33fc090](https://github.com/ReVanced/revanced-patches/commit/33fc09061431d4aa457d743c09a0de31ec566df1))
# [4.14.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.11...v4.14.0-dev.12) (2024-09-14)
### Bug Fixes
* **Soundcloud - Hide ads:** Support latest version ([#3628](https://github.com/ReVanced/revanced-patches/issues/3628)) ([66e7e33](https://github.com/ReVanced/revanced-patches/commit/66e7e33efce9b702fdfcc2b9803e9da8491c1f08))
# [4.14.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.10...v4.14.0-dev.11) (2024-09-12)
### Features
* **Sync for Reddit:** Rename patch to `Use /user/ endpoint` ([98ead49](https://github.com/ReVanced/revanced-patches/commit/98ead493380932cb105530f4ba992673fd364d82))
# [4.14.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.9...v4.14.0-dev.10) (2024-09-12)
### Features
* **Sync for Reddit:** Add `Fix /user/ endpoint` patch ([46d11f3](https://github.com/ReVanced/revanced-patches/commit/46d11f3530fcdae9ed08b7e93aac235638a92dff))
# [4.14.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.8...v4.14.0-dev.9) (2024-09-09)
### Features
* **YouTube:** Add donation link to settings about screen ([#3626](https://github.com/ReVanced/revanced-patches/issues/3626)) ([0684ab5](https://github.com/ReVanced/revanced-patches/commit/0684ab5f183631de5720352049cfd293daa58eb0))
# [4.14.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.7...v4.14.0-dev.8) (2024-09-09)
### Bug Fixes
* **YouTube - SponsorBlock:** Add summary text to 'view my segments' button ([df80b9f](https://github.com/ReVanced/revanced-patches/commit/df80b9f92f0d981b9a40b7756d74f8ccc3dcb1e9))
# [4.14.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.6...v4.14.0-dev.7) (2024-09-06)
### Features
* Add `Check environment` patch ([#3610](https://github.com/ReVanced/revanced-patches/issues/3610)) ([fbcbdaf](https://github.com/ReVanced/revanced-patches/commit/fbcbdafa4938a35b5fdec46aae7b250a84b9c139))
# [4.14.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.5...v4.14.0-dev.6) (2024-09-06)
### Features
* Add `Change data directory location` patch ([#3602](https://github.com/ReVanced/revanced-patches/issues/3602)) ([5998029](https://github.com/ReVanced/revanced-patches/commit/59980292809cc0626bf49a160eeb05a1523c4eda))
# [4.14.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.4...v4.14.0-dev.5) (2024-09-06)
### Bug Fixes
* **Pixiv - Hide ads:** Fix for latest version ([#3616](https://github.com/ReVanced/revanced-patches/issues/3616)) ([98956e8](https://github.com/ReVanced/revanced-patches/commit/98956e8f1a41347bb435720bbf984969469a7110))
# [4.14.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.3...v4.14.0-dev.4) (2024-09-01)
### Bug Fixes
* **YouTube - ReturnYouTubeDislike:** Show estimated like count for videos with hidden likes ([#3601](https://github.com/ReVanced/revanced-patches/issues/3601)) ([005be82](https://github.com/ReVanced/revanced-patches/commit/005be82d71b2a42387b1b57035930b20f4663794))
# [4.14.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.2...v4.14.0-dev.3) (2024-08-30)
### Features
* **YouTube - Keyword filter:** Add syntax to match whole keywords and not substrings ([#3592](https://github.com/ReVanced/revanced-patches/issues/3592)) ([f5fb351](https://github.com/ReVanced/revanced-patches/commit/f5fb3512cfafe214ba6a6d25ba0825ae1884a0ff))
# [4.14.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.14.0-dev.1...v4.14.0-dev.2) (2024-08-24)
### Features
* **Duolingo:** Add `Disable ads` and `Enable debug menu` patch ([#3422](https://github.com/ReVanced/revanced-patches/issues/3422)) ([d0a8599](https://github.com/ReVanced/revanced-patches/commit/d0a8599f76ce653e5d7c98069ad3c58b9ab9c5eb))
# [4.14.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.4-dev.2...v4.14.0-dev.1) (2024-08-22)
### Features
* **YouTube - Spoof client:** Allow forcing AVC codec with iOS ([#3570](https://github.com/ReVanced/revanced-patches/issues/3570)) ([1a49d1f](https://github.com/ReVanced/revanced-patches/commit/1a49d1f3c2a343d05d0abc07c143add486246fd0))
## [4.13.4-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.13.4-dev.1...v4.13.4-dev.2) (2024-08-20)
### Bug Fixes
* **YouTube - SponsorBlock:** Handle if the user enters an invalid number into any SB settings ([37b3dd1](https://github.com/ReVanced/revanced-patches/commit/37b3dd1e789f8bb16fa1b9dd582e39c89dbe730c))
## [4.13.4-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.3...v4.13.4-dev.1) (2024-08-18)
### Bug Fixes
* **SwissID:** Rename `Remove Google Play Integrity Integrity check` to `Remove Google Play Integrity check` ([#3558](https://github.com/ReVanced/revanced-patches/issues/3558)) ([0f5a771](https://github.com/ReVanced/revanced-patches/commit/0f5a771a5cff5684b4a8fd317f4938fe2cf3cbbe))
## [4.13.3](https://github.com/ReVanced/revanced-patches/compare/v4.13.2...v4.13.3) (2024-08-15)
### Bug Fixes
* **YouTube:** Remove translated string that breaks patching ([a48c2db](https://github.com/ReVanced/revanced-patches/commit/a48c2db53d84767c8fd5d569f9ce1c46c2bfd9a1))
## [4.13.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.2...v4.13.3-dev.1) (2024-08-15)
### Bug Fixes
* **YouTube:** Remove translated string that breaks patching ([a48c2db](https://github.com/ReVanced/revanced-patches/commit/a48c2db53d84767c8fd5d569f9ce1c46c2bfd9a1))
## [4.13.2](https://github.com/ReVanced/revanced-patches/compare/v4.13.1...v4.13.2) (2024-08-15)
### Bug Fixes
* **YouTube - GmsCore Support:** Fix patch exception by using correct patch offset ([#3543](https://github.com/ReVanced/revanced-patches/issues/3543)) ([b2b8454](https://github.com/ReVanced/revanced-patches/commit/b2b8454aa992bcb217fb03eb4de5532e0a9bd354))
## [4.13.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.1...v4.13.2-dev.1) (2024-08-15)
### Bug Fixes
* **YouTube - GmsCore Support:** Fix patch exception by using correct patch offset ([#3543](https://github.com/ReVanced/revanced-patches/issues/3543)) ([b2b8454](https://github.com/ReVanced/revanced-patches/commit/b2b8454aa992bcb217fb03eb4de5532e0a9bd354))
## [4.13.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.0...v4.13.1) (2024-08-15)
### Bug Fixes
* **YouTube - Check watch history domain name resolution:** Add compatibility field ([6c598f0](https://github.com/ReVanced/revanced-patches/commit/6c598f084ed90ee1318e4c66d8c1751c797b8e3b))
## [4.13.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.13.0...v4.13.1-dev.1) (2024-08-15)
### Bug Fixes
* **YouTube - Check watch history domain name resolution:** Add compatibility field ([6c598f0](https://github.com/ReVanced/revanced-patches/commit/6c598f084ed90ee1318e4c66d8c1751c797b8e3b))
# [4.13.0](https://github.com/ReVanced/revanced-patches/compare/v4.12.0...v4.13.0) (2024-08-15)
### Bug Fixes
* **YouTube - GmsCore support:** Fix notifications not working by using the correct permissions ([19ddae2](https://github.com/ReVanced/revanced-patches/commit/19ddae2d15e513e18eb1556c468cd94bd197685b))
### Features
* **Google Photos:** Add `Spoof features` patch ([#3459](https://github.com/ReVanced/revanced-patches/issues/3459)) ([7c218cd](https://github.com/ReVanced/revanced-patches/commit/7c218cd168aa72eb99bcb47d12dfa45616e8ad88))
* **SCB Easy:** Remove broken `Remove debugging detection` patch ([#3518](https://github.com/ReVanced/revanced-patches/issues/3518)) ([f4e23cb](https://github.com/ReVanced/revanced-patches/commit/f4e23cbb8a24638318d8cee20a1991c51855d9d2))
* **YouTube:** Add `Check watch history domain name resolution` patch ([#3537](https://github.com/ReVanced/revanced-patches/issues/3537)) ([2af1425](https://github.com/ReVanced/revanced-patches/commit/2af142525cda07a131335faadd4b3889979fd077))
# [4.13.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.13.0-dev.1...v4.13.0-dev.2) (2024-08-15)
### Features
* **YouTube:** Add `Check watch history domain name resolution` patch ([#3537](https://github.com/ReVanced/revanced-patches/issues/3537)) ([2af1425](https://github.com/ReVanced/revanced-patches/commit/2af142525cda07a131335faadd4b3889979fd077))
# [4.13.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.12.1-dev.1...v4.13.0-dev.1) (2024-08-15)
### Features
* **Google Photos:** Add `Spoof features` patch ([#3459](https://github.com/ReVanced/revanced-patches/issues/3459)) ([7c218cd](https://github.com/ReVanced/revanced-patches/commit/7c218cd168aa72eb99bcb47d12dfa45616e8ad88))
* **SCB Easy:** Remove broken `Remove debugging detection` patch ([#3518](https://github.com/ReVanced/revanced-patches/issues/3518)) ([f4e23cb](https://github.com/ReVanced/revanced-patches/commit/f4e23cbb8a24638318d8cee20a1991c51855d9d2))
## [4.12.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.12.0...v4.12.1-dev.1) (2024-08-15)
### Bug Fixes
* **YouTube - GmsCore support:** Fix notifications not working by using the correct permissions ([19ddae2](https://github.com/ReVanced/revanced-patches/commit/19ddae2d15e513e18eb1556c468cd94bd197685b))
# [4.12.0](https://github.com/ReVanced/revanced-patches/compare/v4.11.0...v4.12.0) (2024-08-06)
### Bug Fixes
* **Google Photos - GmsCore support:** Fix by checking first if a method exists before trying to patch it ([acf38ca](https://github.com/ReVanced/revanced-patches/commit/acf38cafae5eb9896b43f3a6cbd808ac273cd081))
* **Instagram - Hide ads:** Restore compatibility with latest version by fixing fingerprint ([#3455](https://github.com/ReVanced/revanced-patches/issues/3455)) ([4505fa4](https://github.com/ReVanced/revanced-patches/commit/4505fa4138bb55c8957790239c01b8dda63d6cdd))
* **Messenger - Disable switching emoji to sticker:** Constrain to last working version `439.0.0.29.119` ([6207c31](https://github.com/ReVanced/revanced-patches/commit/6207c314c657a1188d1081b0a196a61e49cad83b))
* **SoundCloud - Enable offline sync:** Stop crashing by reversing order of patching instructions from last to first to retain indices ([63b6ced](https://github.com/ReVanced/revanced-patches/commit/63b6cede5fa5bcf377ced422da4e861996a41f0d))
* **YouTube - Bypass image region restrictions:** Move setting to `Misc` menu ([094ae59](https://github.com/ReVanced/revanced-patches/commit/094ae59fc92663fff6c5d6f5cbece41822a326f9))
* **YouTube - Client Spoof:** Restore missing high qualities by spoofing the iOS client user agent ([#3468](https://github.com/ReVanced/revanced-patches/issues/3468)) ([0e6ae5f](https://github.com/ReVanced/revanced-patches/commit/0e6ae5fee752a76604cf9b95f9a76c0cbe5f7dae))
* **YouTube - Hide keyword content:** Do not hide flyout menu ([687c9f7](https://github.com/ReVanced/revanced-patches/commit/687c9f7eb03cca5f7b3486f07f2e3453ebc77faf))
* **YouTube - SponsorBlock:** Correctly show minute timestamp when creating a new segment ([d74c366](https://github.com/ReVanced/revanced-patches/commit/d74c366dbf5f25c20fbfc5a0157c3c15dda82a16))
* **YouTube - SponsorBlock:** Improve create segment manual seek accuracy ([#3491](https://github.com/ReVanced/revanced-patches/issues/3491)) ([1544981](https://github.com/ReVanced/revanced-patches/commit/15449819ff74b636fb2fa6aacd770142c51d2e5d))
* **YouTube - Spoof client:** Fix tracking history on brand accounts ([#3480](https://github.com/ReVanced/revanced-patches/issues/3480)) ([69c1f16](https://github.com/ReVanced/revanced-patches/commit/69c1f16f7eb0d5759a44f7f7a09b1757ce8f61dd))
* **YouTube - Spoof client:** Restore livestream audio only playback with iOS spoofing ([#3504](https://github.com/ReVanced/revanced-patches/issues/3504)) ([90d3288](https://github.com/ReVanced/revanced-patches/commit/90d32880906787d82c4b9a7a1099b46dff3a0870))
### Features
* Add `Hide mock location` patch ([#3417](https://github.com/ReVanced/revanced-patches/issues/3417)) ([5f81b40](https://github.com/ReVanced/revanced-patches/commit/5f81b40e7d5567fb5689d08ccc9caeaa267c3143))
* Add `Spoof build info` patch ([e7829b4](https://github.com/ReVanced/revanced-patches/commit/e7829b41e782c9feda23b9d6acf48bae277d24d9))
* **Boost for Reddit:** Add `Disable ads` patch ([#3474](https://github.com/ReVanced/revanced-patches/issues/3474)) ([b292c20](https://github.com/ReVanced/revanced-patches/commit/b292c200bf4ea5b4f71d96690ac011e7843552f0))
* **CandyLink:** Remove non-functional `Unlock pro` patch ([7ae9f8f](https://github.com/ReVanced/revanced-patches/commit/7ae9f8fa0a349b91853e9554f18e564ca6ff887c))
* **Expense Manager:** Remove non-functional `Unlock pro` patch ([ebbcac7](https://github.com/ReVanced/revanced-patches/commit/ebbcac74fd8598daebb4be0bd7c430c41333e2d4))
* **Google News:** Add `Enable CustomTabs` and `GmsCore support` patch ([#3111](https://github.com/ReVanced/revanced-patches/issues/3111)) ([ad59096](https://github.com/ReVanced/revanced-patches/commit/ad590962275f888b335252ad5bed0f34e959d3c7))
* **Google Photos:** Add `GmsCore support` patch ([#3414](https://github.com/ReVanced/revanced-patches/issues/3414)) ([24528e0](https://github.com/ReVanced/revanced-patches/commit/24528e0a6eec17ce0a3c52f8862585933615ad28))
* **Instagram:** Remove unnecessary `Hide timeline ads` patch ([5e1d001](https://github.com/ReVanced/revanced-patches/commit/5e1d001056df68e1e2b39f1365215c91bcc9e46b))
* **SoundCloud:** Add `Enable offline sync` patch ([#3407](https://github.com/ReVanced/revanced-patches/issues/3407)) ([4de86c6](https://github.com/ReVanced/revanced-patches/commit/4de86c6407376bcd3cc0513a2f0707410b8d7ccd))
* **SwissID:** Add `Remove Google Play Integrity Integrity check` patch ([#3478](https://github.com/ReVanced/revanced-patches/issues/3478)) ([60492ae](https://github.com/ReVanced/revanced-patches/commit/60492aea7863e07d8bf1af9380ae9295ca161f3c))
* **YouTube - Description components:** Add `Hide 'Key concepts' section` option ([#3495](https://github.com/ReVanced/revanced-patches/issues/3495)) ([d75b645](https://github.com/ReVanced/revanced-patches/commit/d75b64595a7ac26faca4c0ae21923b22f6783975))
* **YouTube:** Add `Bypass image region restrictions` patch ([#3442](https://github.com/ReVanced/revanced-patches/issues/3442)) ([765fab2](https://github.com/ReVanced/revanced-patches/commit/765fab2af2769349446cc0f2109343ef3bd8c621))
# [4.12.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.16...v4.12.0-dev.17) (2024-08-06)
### Bug Fixes
* **Google Photos - GmsCore support:** Fix by checking first if a method exists before trying to patch it ([acf38ca](https://github.com/ReVanced/revanced-patches/commit/acf38cafae5eb9896b43f3a6cbd808ac273cd081))
* **Messenger - Disable switching emoji to sticker:** Constrain to last working version `439.0.0.29.119` ([6207c31](https://github.com/ReVanced/revanced-patches/commit/6207c314c657a1188d1081b0a196a61e49cad83b))
### Features
* **CandyLink:** Remove non-functional `Unlock pro` patch ([7ae9f8f](https://github.com/ReVanced/revanced-patches/commit/7ae9f8fa0a349b91853e9554f18e564ca6ff887c))
* **Expense Manager:** Remove non-functional `Unlock pro` patch ([ebbcac7](https://github.com/ReVanced/revanced-patches/commit/ebbcac74fd8598daebb4be0bd7c430c41333e2d4))
* **Instagram:** Remove unnecessary `Hide timeline ads` patch ([5e1d001](https://github.com/ReVanced/revanced-patches/commit/5e1d001056df68e1e2b39f1365215c91bcc9e46b))
# [4.12.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.15...v4.12.0-dev.16) (2024-08-04)
### Bug Fixes
* **YouTube - Spoof client:** Restore livestream audio only playback with iOS spoofing ([#3504](https://github.com/ReVanced/revanced-patches/issues/3504)) ([90d3288](https://github.com/ReVanced/revanced-patches/commit/90d32880906787d82c4b9a7a1099b46dff3a0870))
# [4.12.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.14...v4.12.0-dev.15) (2024-08-02)
### Bug Fixes
* **YouTube - SponsorBlock:** Improve create segment manual seek accuracy ([#3491](https://github.com/ReVanced/revanced-patches/issues/3491)) ([1544981](https://github.com/ReVanced/revanced-patches/commit/15449819ff74b636fb2fa6aacd770142c51d2e5d))
# [4.12.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.13...v4.12.0-dev.14) (2024-08-01)
### Features
* **YouTube - Description components:** Add `Hide 'Key concepts' section` option ([#3495](https://github.com/ReVanced/revanced-patches/issues/3495)) ([d75b645](https://github.com/ReVanced/revanced-patches/commit/d75b64595a7ac26faca4c0ae21923b22f6783975))
# [4.12.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.12...v4.12.0-dev.13) (2024-07-31)

View File

@@ -16,6 +16,14 @@ public final class app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPat
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Triple;)V
}
public final class app/revanced/patches/all/directory/ChangeDataDirectoryLocationPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
public static final field INSTANCE Lapp/revanced/patches/all/directory/ChangeDataDirectoryLocationPatch;
public fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Integer;
public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object;
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V
}
public final class app/revanced/patches/all/interaction/gestures/PredictiveBackGesturePatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/all/interaction/gestures/PredictiveBackGesturePatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
@@ -243,6 +251,18 @@ public final class app/revanced/patches/cieid/restrictions/root/BypassRootChecks
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/duolingo/ad/DisableAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/duolingo/ad/DisableAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/duolingo/debug/EnableDebugMenuPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/facebook/ads/story/HideStoryAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/facebook/ads/story/HideStoryAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -279,6 +299,16 @@ public final class app/revanced/patches/googlenews/misc/integrations/Integration
public static final field INSTANCE Lapp/revanced/patches/googlenews/misc/integrations/IntegrationsPatch;
}
public final class app/revanced/patches/googlephotos/features/SpoofFeaturesPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/googlephotos/features/SpoofFeaturesPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/googlephotos/features/fingerprints/InitializeFeaturesEnumFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint {
public static final field INSTANCE Lapp/revanced/patches/googlephotos/features/fingerprints/InitializeFeaturesEnumFingerprint;
}
public final class app/revanced/patches/googlephotos/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch {
public static final field INSTANCE Lapp/revanced/patches/googlephotos/misc/gms/GmsCoreSupportPatch;
}
@@ -423,6 +453,12 @@ public final class app/revanced/patches/music/ad/video/HideMusicVideoAds : app/r
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/music/ad/video/HideVideoAds : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/ad/video/HideVideoAds;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/music/ad/video/MusicVideoAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/music/ad/video/MusicVideoAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -792,6 +828,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/s
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch;
}
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/user/UseUserEndpointPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/user/UseUserEndpointPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch;
}
@@ -826,6 +868,12 @@ public final class app/revanced/patches/serviceportalbund/detection/root/RootDet
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public abstract class app/revanced/patches/shared/misc/checks/BaseCheckEnvironmentPatch : app/revanced/patcher/patch/BytecodePatch {
public fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Lapp/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch;)V
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -1834,6 +1882,10 @@ public final class app/revanced/patches/youtube/misc/backgroundplayback/Backgrou
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/youtube/misc/check/CheckEnvironmentPatch : app/revanced/patches/shared/misc/checks/BaseCheckEnvironmentPatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/check/CheckEnvironmentPatch;
}
public final class app/revanced/patches/youtube/misc/debugging/DebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/debugging/DebuggingPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
@@ -1864,6 +1916,12 @@ public final class app/revanced/patches/youtube/misc/fix/playback/SpoofSignature
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
}
public final class app/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/SpoofVideoStreamsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/UserAgentClientSpoofPatch;
public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object;
@@ -2104,6 +2162,7 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat
}
public final class app/revanced/util/BytecodeUtilsKt {
public static final fun alsoResolve (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/data/BytecodeContext;Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;

View File

@@ -31,6 +31,8 @@ dependencies {
implementation(libs.guava)
// Used in JsonGenerator.
implementation(libs.gson)
// Android API stubs defined here.
compileOnly(project(":stub"))
}
kotlin {

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 4.12.0-dev.13
version = 4.14.0-dev.15

File diff suppressed because one or more lines are too long

View File

@@ -5,3 +5,5 @@ buildCache {
isEnabled = "CI" !in System.getenv()
}
}
include(":stub")

View File

@@ -0,0 +1,73 @@
package app.revanced.patches.all.directory
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
@Patch(
name = "Change data directory location",
description = "Changes the data directory in the application from " +
"the app internal storage directory to /sdcard/android/data accessible by root-less devices." +
"Using this patch can cause unexpected issues with some apps.",
use = false,
)
@Suppress("unused")
object ChangeDataDirectoryLocationPatch : BaseTransformInstructionsPatch<Int>() {
override fun filterMap(
classDef: ClassDef,
method: Method,
instruction: Instruction,
instructionIndex: Int,
): Int? {
val reference = instruction.getReference<MethodReference>() ?: return null
if (!MethodUtil.methodSignaturesMatch(reference, MethodCall.GetDir.reference)) {
return null
}
return instructionIndex
}
override fun transform(
mutableMethod: MutableMethod,
entry: Int,
) = transformMethodCall(entry, mutableMethod)
private fun transformMethodCall(
instructionIndex: Int,
mutableMethod: MutableMethod,
) {
val getDirInstruction = mutableMethod.getInstruction<Instruction35c>(instructionIndex)
val contextRegister = getDirInstruction.registerC
val dataRegister = getDirInstruction.registerD
mutableMethod.replaceInstruction(
instructionIndex,
"invoke-virtual { v$contextRegister, v$dataRegister }, " +
"Landroid/content/Context;->getExternalFilesDir(Ljava/lang/String;)Ljava/io/File;",
)
}
private enum class MethodCall(
val reference: MethodReference,
) {
GetDir(
ImmutableMethodReference(
"Landroid/content/Context;",
"getDir",
listOf("Ljava/lang/String;", "I"),
"Ljava/io/File;",
),
),
}
}

View File

@@ -83,8 +83,9 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
"eu-rES" to "eu",
"fa-rIR" to "fa",
"fi-rFI" to "fi",
"tl-rPH" to "tl",
"fil-rPH" to "tl",
"fr-rFR" to "fr",
"ga-rIE" to "ga",
"gl-rES" to "gl",
"gu-rIN" to "gu",
"hi-rIN" to "hi",
@@ -125,6 +126,7 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
"sk-rSK" to "sk",
"sl-rSI" to "sl",
"sq-rAL" to "sq",
"sr-rCS" to "b+sr+Latn",
"sr-rSP" to "sr",
"sv-rSE" to "sv",
"sw-rKE" to "sw",
@@ -138,7 +140,6 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
"uz-rUZ" to "uz",
"vi-rVN" to "vi",
"zh-rCN" to "zh-rCN",
"zh-rHK" to "zh-rHK",
"zh-rTW" to "zh-rTW",
"zu-rZA" to "zu",
)

View File

@@ -1,20 +1,23 @@
package app.revanced.patches.candylinkvpn
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.candylinkvpn.fingerprints.IsPremiumPurchasedFingerprint
import app.revanced.util.exception
@Patch(
name = "Unlock pro",
compatiblePackages = [CompatiblePackage("com.candylink.openvpn")]
compatiblePackages = [CompatiblePackage("com.candylink.openvpn")],
)
@Deprecated(
"This patch does not work anymore and will be removed in the future, " +
"because the servers now check the purchase status.",
)
@Suppress("unused")
object UnlockProPatch : BytecodePatch(
setOf(IsPremiumPurchasedFingerprint)
setOf(IsPremiumPurchasedFingerprint),
) {
override fun execute(context: BytecodeContext) {
IsPremiumPurchasedFingerprint.result?.mutableMethod?.addInstructions(
@@ -22,7 +25,7 @@ object UnlockProPatch : BytecodePatch(
"""
const/4 v0, 0x1
return v0
"""
""",
) ?: throw IsPremiumPurchasedFingerprint.exception
}
}
}

View File

@@ -0,0 +1,41 @@
package app.revanced.patches.duolingo.ad
import app.revanced.patcher.data.BytecodeContext
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.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.duolingo.ad.fingerprints.InitializeMonetizationDebugSettingsFingerprint
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch(
name = "Disable ads",
compatiblePackages = [CompatiblePackage("com.duolingo")]
)
@Suppress("unused")
object DisableAdsPatch : BytecodePatch(
setOf(InitializeMonetizationDebugSettingsFingerprint)
) {
override fun execute(context: BytecodeContext) {
// Couple approaches to remove ads exist:
//
// MonetizationDebugSettings has a boolean value for "disableAds".
// OnboardingState has a getter to check if the user has any "adFreeSessions".
// SharedPreferences has a debug boolean value with key "disable_ads", which maps to "DebugCategory.DISABLE_ADS".
//
// MonetizationDebugSettings seems to be the most general setting to work fine.
InitializeMonetizationDebugSettingsFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex,
"const/4 v$register, 0x1"
)
}
}
}
}

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.duolingo.ad.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object InitializeMonetizationDebugSettingsFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf(
"Z", // disableAds
"Z", // useDebugBilling
"Z", // showManageSubscriptions
"Z", // alwaysShowSuperAds
"Lcom/duolingo/debug/FamilyQuestOverride;",
),
opcodes = listOf(
Opcode.IPUT_BOOLEAN
)
)

View File

@@ -0,0 +1,35 @@
package app.revanced.patches.duolingo.debug
import app.revanced.patcher.data.BytecodeContext
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.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.duolingo.debug.fingerprints.InitializeBuildConfigProviderFingerprint
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch(
name = "Enable debug menu",
compatiblePackages = [CompatiblePackage("com.duolingo", ["5.158.4"])],
use = false
)
@Suppress("unused")
object EnableDebugMenuPatch : BytecodePatch(
setOf(InitializeBuildConfigProviderFingerprint)
) {
override fun execute(context: BytecodeContext) {
InitializeBuildConfigProviderFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex,
"const/4 v$register, 0x1"
)
}
}
}
}

View File

@@ -0,0 +1,25 @@
package app.revanced.patches.duolingo.debug.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* The `BuildConfigProvider` class has two booleans:
*
* - `isChina`: (usually) compares "play" with "china"...except for builds in China
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true`
*/
internal object InitializeBuildConfigProviderFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
strings = listOf(
"debug",
"release",
"china",
),
opcodes = listOf(
Opcode.IPUT_BOOLEAN
)
)

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.googlephotos.features
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.misc.build.BaseSpoofBuildInfoPatch
@Patch(description = "Spoof build info to Google Pixel XL.")
internal class SpoofBuildInfoPatch : BaseSpoofBuildInfoPatch() {
override val brand = "google"
override val manufacturer = "Google"
override val device = "marlin"
override val product = "marlin"
override val model = "Pixel XL"
override val fingerprint = "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys"
}

View File

@@ -0,0 +1,87 @@
package app.revanced.patches.googlephotos.features
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringArrayPatchOption
import app.revanced.patches.googlephotos.features.fingerprints.InitializeFeaturesEnumFingerprint
import app.revanced.util.getReference
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Patch(
name = "Spoof features",
description = "Spoofs the device to enable Google Pixel exclusive features, including unlimited storage.",
dependencies = [SpoofBuildInfoPatch::class],
compatiblePackages = [CompatiblePackage("com.google.android.apps.photos")],
)
@Suppress("unused")
object SpoofFeaturesPatch : BytecodePatch(setOf(InitializeFeaturesEnumFingerprint)) {
private val featuresToEnable by stringArrayPatchOption(
"featuresToEnable",
arrayOf(
"com.google.android.apps.photos.NEXUS_PRELOAD",
"com.google.android.apps.photos.nexus_preload",
),
title = "Features to enable",
description = "Google Pixel exclusive features to enable. Features up to Pixel XL enable the unlimited storage feature.",
required = true,
)
private val featuresToDisable by stringArrayPatchOption(
"featuresToDisable",
arrayOf(
"com.google.android.apps.photos.PIXEL_2017_PRELOAD",
"com.google.android.apps.photos.PIXEL_2018_PRELOAD",
"com.google.android.apps.photos.PIXEL_2019_MIDYEAR_PRELOAD",
"com.google.android.apps.photos.PIXEL_2019_PRELOAD",
"com.google.android.feature.PIXEL_2020_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2020_EXPERIENCE",
"com.google.android.feature.PIXEL_2021_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2021_EXPERIENCE",
"com.google.android.feature.PIXEL_2022_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2022_EXPERIENCE",
"com.google.android.feature.PIXEL_2023_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2023_EXPERIENCE",
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
),
title = "Features to disable",
description = "Google Pixel exclusive features to disable." +
"Features after Pixel XL may have to be disabled for unlimited storage depending on the device.",
required = true,
)
override fun execute(context: BytecodeContext) {
val featuresToEnable = featuresToEnable!!.toSet()
val featuresToDisable = featuresToDisable!!.toSet()
InitializeFeaturesEnumFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
getInstructions().filter { it.opcode == Opcode.CONST_STRING }.forEach {
val feature = it.getReference<StringReference>()!!.string
val spoofedFeature = when (feature) {
in featuresToEnable -> "android.hardware.wifi"
in featuresToDisable -> "dummy"
else -> return@forEach
}
val constStringIndex = it.location.index
val constStringRegister = (it as OneRegisterInstruction).registerA
replaceInstruction(
constStringIndex,
"const-string v$constStringRegister, \"$spoofedFeature\"",
)
}
}
}
}
}

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.googlephotos.features.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
object InitializeFeaturesEnumFingerprint : MethodFingerprint(
strings = listOf("com.google.android.apps.photos.NEXUS_PRELOAD"),
)

View File

@@ -10,7 +10,7 @@ import app.revanced.util.exception
@Patch(
name = "Hide ads",
description = "Hides ads in stories, discover, profile, etc." +
description = "Hides ads in stories, discover, profile, etc. " +
"An ad can still appear once when refreshing the home feed.",
compatiblePackages = [CompatiblePackage("com.instagram.android")],
)

View File

@@ -14,9 +14,9 @@ import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch(
name = "Hide timeline ads",
compatiblePackages = [CompatiblePackage("com.instagram.android")],
)
@Deprecated("This patch is not needed anymore.", replaceWith = ReplaceWith("HideAdsPatch"))
@Suppress("unused")
object HideTimelineAdsPatch : BytecodePatch(
setOf(

View File

@@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch(
name = "Disable switching emoji to sticker",
description = "Disables switching from emoji to sticker search mode in message input field.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")],
compatiblePackages = [CompatiblePackage("com.facebook.orca", ["439.0.0.29.119"])],
)
@Suppress("unused")
object DisableSwitchingEmojiToStickerPatch : BytecodePatch(

View File

@@ -8,20 +8,20 @@ import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.moneymanager.fingerprints.UnlockProFingerprint
@Patch(
name = "Unlock pro",
compatiblePackages = [CompatiblePackage("com.ithebk.expensemanager")]
compatiblePackages = [CompatiblePackage("com.ithebk.expensemanager")],
)
@Deprecated("This patch is not functional anymore and will be removed in the future.")
@Suppress("unused")
object UnlockProPatch : BytecodePatch(
setOf(UnlockProFingerprint)
){
setOf(UnlockProFingerprint),
) {
override fun execute(context: BytecodeContext) {
UnlockProFingerprint.result!!.mutableMethod.addInstructions(
UnlockProFingerprint.result!!.mutableMethod.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
""",
)
}
}
}

View File

@@ -6,43 +6,43 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsParentFingerprint
import app.revanced.patches.music.ad.video.fingerprints.ShowVideoAdsParentFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide music video ads",
name = "Hide video ads",
description = "Hides ads that appear while listening to or streaming music videos, podcasts, or songs.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
],
)
@Suppress("unused")
object HideMusicVideoAds : BytecodePatch(
setOf(ShowMusicVideoAdsParentFingerprint),
object HideVideoAds : BytecodePatch(
setOf(ShowVideoAdsParentFingerprint),
) {
override fun execute(context: BytecodeContext) {
ShowMusicVideoAdsParentFingerprint.result?.let {
val showMusicVideoAdsMethod = context
ShowVideoAdsParentFingerprint.result?.let {
val showVideoAdsMethod = context
.toMethodWalker(it.mutableMethod)
.nextMethod(it.scanResult.patternScanResult!!.startIndex + 1, true).getMethod() as MutableMethod
showMusicVideoAdsMethod.addInstruction(0, "const/4 p1, 0x0")
} ?: throw ShowMusicVideoAdsParentFingerprint.exception
showVideoAdsMethod.addInstruction(0, "const/4 p1, 0x0")
} ?: throw ShowVideoAdsParentFingerprint.exception
}
}
@Deprecated("This patch class has been renamed to HideMusicVideoAds.")
@Deprecated("This patch class has been renamed to HideVideoAds.")
object HideMusicVideoAds : BytecodePatch(
dependencies = setOf(HideVideoAds::class)
) {
override fun execute(context: BytecodeContext) {
}
}
@Deprecated("This patch class has been renamed to HideVideoAds.")
object MusicVideoAdsPatch : BytecodePatch(
dependencies = setOf(HideMusicVideoAds::class),
) {
override fun execute(context: BytecodeContext) {
}
}
}

View File

@@ -3,7 +3,7 @@ package app.revanced.patches.music.ad.video.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object ShowMusicVideoAdsParentFingerprint : MethodFingerprint(
internal object ShowVideoAdsParentFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,

View File

@@ -12,16 +12,7 @@ import com.android.tools.smali.dexlib2.Opcode
@Patch(
description = "Adds more audio codec options. The new audio codecs usually result in better audio quality.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
]
)
@Deprecated("This patch is no longer needed as the feature is now enabled by default.")

View File

@@ -12,16 +12,7 @@ import app.revanced.util.exception
name = "Enable exclusive audio playback",
description = "Enables the option to play audio without video.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
]
)
@Suppress("unused")

View File

@@ -14,16 +14,7 @@ import app.revanced.patches.music.interaction.permanentrepeat.fingerprints.Repea
name = "Permanent repeat",
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
],
use = false
)

View File

@@ -14,16 +14,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
name = "Hide category bar",
description = "Hides the category bar at the top of the homepage.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
],
use = false,
)

View File

@@ -17,16 +17,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
name = "Hide 'Get Music Premium' label",
description = "Hides the \"Get Music Premium\" label from the account menu and settings.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
]
)
@Suppress("unused")

View File

@@ -23,16 +23,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
name = "Remove upgrade button",
description = "Removes the upgrade tab from the pivot bar.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
]
)
@Suppress("unused")

View File

@@ -13,16 +13,7 @@ import app.revanced.patches.music.misc.androidauto.fingerprints.CheckCertificate
name = "Bypass certificate checks",
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
]
)
@Suppress("unused")

View File

@@ -14,16 +14,7 @@ import app.revanced.util.resultOrThrow
name = "Remove background playback restrictions",
description = "Removes restrictions on background playback, including playing kids videos in the background.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
CompatiblePackage("com.google.android.apps.youtube.music")
]
)
@Suppress("unused")

View File

@@ -23,16 +23,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
integrationsPatchDependency = IntegrationsPatch::class,
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
compatiblePackages = setOf(
CompatiblePackage(
"com.google.android.apps.youtube.music",
setOf(
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
),
),
CompatiblePackage("com.google.android.apps.youtube.music"),
),
fingerprints = setOf(
CastDynamiteModuleV2Fingerprint,

View File

@@ -11,7 +11,7 @@ import app.revanced.util.exception
@Patch(
name = "Spoof Android device ID",
description = "Spoofs the Android device ID used by the app for account authentication." +
description = "Spoofs the Android device ID used by the app for account authentication. " +
"This can be used to copy the account to another device.",
compatiblePackages = [
CompatiblePackage(

View File

@@ -1,28 +1,25 @@
package app.revanced.patches.pixiv.ads
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.pixiv.ads.fingerprints.IsNotPremiumFingerprint
import app.revanced.patches.pixiv.ads.fingerprints.ShouldShowAdsFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide ads",
compatiblePackages = [CompatiblePackage("jp.pxv.android")]
compatiblePackages = [CompatiblePackage("jp.pxv.android")],
)
@Suppress("unused")
object HideAdsPatch : BytecodePatch(setOf(IsNotPremiumFingerprint)) {
// Always return false in the "isNotPremium" method which normally returns !this.accountManager.isPremium.
// However, this is not the method that controls the user's premium status.
// Instead, this method is used to determine whether ads should be shown.
object HideAdsPatch : BytecodePatch(setOf(ShouldShowAdsFingerprint)) {
override fun execute(context: BytecodeContext) =
IsNotPremiumFingerprint.result?.mutableClass?.virtualMethods?.first()?.addInstructions(
ShouldShowAdsFingerprint.result?.mutableMethod?.addInstructions(
0,
"""
const/4 v0, 0x0
return v0
"""
) ?: throw IsNotPremiumFingerprint.exception
}
""",
) ?: throw ShouldShowAdsFingerprint.exception
}

View File

@@ -1,21 +0,0 @@
package app.revanced.patches.pixiv.ads.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object IsNotPremiumFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
listOf("L"),
strings = listOf("pixivAccountManager"),
customFingerprint = custom@{ _, classDef ->
// The "isNotPremium" method is the only method in the class.
if (classDef.virtualMethods.count() != 1) return@custom false
classDef.virtualMethods.first().let { isNotPremiumMethod ->
isNotPremiumMethod.parameterTypes.size == 0 && isNotPremiumMethod.returnType == "Z"
}
}
)

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.pixiv.ads.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object ShouldShowAdsFingerprint : MethodFingerprint(
"Z",
AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef, classDef ->
classDef.type.endsWith("AdUtils;") && methodDef.name == "shouldShowAds"
}
)

View File

@@ -0,0 +1,61 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints.*
import app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints.OAuthFriendRequestFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints.OAuthSubredditInfoRequestHelperFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints.OAuthUnfriendRequestFingerprint
import app.revanced.util.getReference
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Patch(
name = "Use /user/ endpoint",
description = "Replaces the deprecated endpoint for viewing user profiles /u with /user, that used to fix a bug.",
compatiblePackages = [
CompatiblePackage("com.laurencedawson.reddit_sync"),
CompatiblePackage("com.laurencedawson.reddit_sync.pro"),
CompatiblePackage("com.laurencedawson.reddit_sync.dev"),
],
use = false,
)
@Suppress("unused")
object UseUserEndpointPatch : BytecodePatch(
fingerprints = setOf(
OAuthFriendRequestFingerprint,
OAuthSubredditInfoRequestConstructorFingerprint,
OAuthSubredditInfoRequestHelperFingerprint,
OAuthUnfriendRequestFingerprint,
OAuthUserIdRequestFingerprint,
OAuthUserInfoRequestFingerprint,
),
) {
override fun execute(context: BytecodeContext) {
arrayOf(
OAuthFriendRequestFingerprint,
OAuthSubredditInfoRequestConstructorFingerprint,
OAuthSubredditInfoRequestHelperFingerprint,
OAuthUnfriendRequestFingerprint,
OAuthUserIdRequestFingerprint,
OAuthUserInfoRequestFingerprint,
).map(MethodFingerprint::resultOrThrow).map {
it.scanResult.stringsScanResult!!.matches.first().index to it.mutableMethod
}.forEach { (userPathStringIndex, method) ->
val userPathStringInstruction = method.getInstruction<OneRegisterInstruction>(userPathStringIndex)
val userPathStringRegister = userPathStringInstruction.registerA
val fixedUserPathString = userPathStringInstruction.getReference<StringReference>()!!.string.replace("u/", "user/")
method.replaceInstruction(
userPathStringIndex,
"const-string v$userPathStringRegister, \"${fixedUserPathString}\"",
)
}
}
}

View File

@@ -0,0 +1,10 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal abstract class BaseUserEndpointFingerprint(source: String, accessFlags: Int? = null) :
MethodFingerprint(
accessFlags = accessFlags,
strings = listOf("u/"),
customFingerprint = { _, classDef -> classDef.sourceFile == source },
)

View File

@@ -0,0 +1,3 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
internal object OAuthFriendRequestFingerprint : BaseUserEndpointFingerprint("OAuthFriendRequest.java")

View File

@@ -0,0 +1,10 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
import app.revanced.patcher.extensions.or
import com.android.tools.smali.dexlib2.AccessFlags
internal object OAuthSubredditInfoRequestConstructorFingerprint :
BaseUserEndpointFingerprint(
"OAuthSubredditInfoRequest.java",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
)

View File

@@ -0,0 +1,10 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
import app.revanced.patcher.extensions.or
import com.android.tools.smali.dexlib2.AccessFlags
internal object OAuthSubredditInfoRequestHelperFingerprint :
BaseUserEndpointFingerprint(
"OAuthSubredditInfoRequest.java",
AccessFlags.PRIVATE or AccessFlags.STATIC,
)

View File

@@ -0,0 +1,3 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
internal object OAuthUnfriendRequestFingerprint : BaseUserEndpointFingerprint("OAuthUnfriendRequest.java")

View File

@@ -0,0 +1,3 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
internal object OAuthUserIdRequestFingerprint : BaseUserEndpointFingerprint("OAuthUserIdRequest.java")

View File

@@ -0,0 +1,3 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.user.fingerprints
internal object OAuthUserInfoRequestFingerprint : BaseUserEndpointFingerprint("OAuthUserInfoRequest.java")

View File

@@ -10,11 +10,13 @@ import app.revanced.patches.scbeasy.detection.debugging.fingerprints.DebuggingDe
@Patch(
use = false,
name = "Remove debugging detection",
description = "Removes the USB and wireless debugging checks.",
compatiblePackages = [CompatiblePackage("com.scb.phone")]
)
@Suppress("unused")
@Deprecated("This patch no longer work and will be removed in the future " +
"due to the complexity of the application.\n" +
"See https://github.com/ReVanced/revanced-patches/issues/3517 for more details.")
object RemoveDebuggingDetectionPatch : BytecodePatch(
setOf(DebuggingDetectionFingerprint)
) {

View File

@@ -0,0 +1,116 @@
package app.revanced.patches.shared.misc.checks
import android.os.Build.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableLongEncodedValue
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableStringEncodedValue
import app.revanced.patches.all.misc.resources.AddResourcesPatch
import app.revanced.patches.shared.misc.checks.fingerprints.PatchInfoBuildFingerprint
import app.revanced.patches.shared.misc.checks.fingerprints.PatchInfoFingerprint
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
import app.revanced.util.exception
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.immutable.value.ImmutableLongEncodedValue
import com.android.tools.smali.dexlib2.immutable.value.ImmutableStringEncodedValue
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
abstract class BaseCheckEnvironmentPatch(
private val mainActivityOnCreateFingerprint: MethodFingerprint,
compatiblePackages: Set<CompatiblePackage>,
integrationsPatch: BaseIntegrationsPatch,
) : BytecodePatch(
description = "Checks, if the application was patched by, otherwise warns the user.",
compatiblePackages = compatiblePackages,
dependencies = setOf(
AddResourcesPatch::class,
integrationsPatch::class,
),
fingerprints = setOf(
PatchInfoFingerprint,
PatchInfoBuildFingerprint,
mainActivityOnCreateFingerprint,
),
) {
override fun execute(context: BytecodeContext) {
AddResourcesPatch(BaseCheckEnvironmentPatch::class)
setPatchInfo()
invokeCheck()
}
private fun setPatchInfo() {
PatchInfoFingerprint.setClassFields(
"PATCH_TIME" to System.currentTimeMillis().encoded,
)
fun setBuildInfo() {
PatchInfoBuildFingerprint.setClassFields(
"PATCH_BOARD" to BOARD.encodedAndHashed,
"PATCH_BOOTLOADER" to BOOTLOADER.encodedAndHashed,
"PATCH_BRAND" to BRAND.encodedAndHashed,
"PATCH_CPU_ABI" to CPU_ABI.encodedAndHashed,
"PATCH_CPU_ABI2" to CPU_ABI2.encodedAndHashed,
"PATCH_DEVICE" to DEVICE.encodedAndHashed,
"PATCH_DISPLAY" to DISPLAY.encodedAndHashed,
"PATCH_FINGERPRINT" to FINGERPRINT.encodedAndHashed,
"PATCH_HARDWARE" to HARDWARE.encodedAndHashed,
"PATCH_HOST" to HOST.encodedAndHashed,
"PATCH_ID" to ID.encodedAndHashed,
"PATCH_MANUFACTURER" to MANUFACTURER.encodedAndHashed,
"PATCH_MODEL" to MODEL.encodedAndHashed,
"PATCH_ODM_SKU" to ODM_SKU.encodedAndHashed,
"PATCH_PRODUCT" to PRODUCT.encodedAndHashed,
"PATCH_RADIO" to RADIO.encodedAndHashed,
"PATCH_SKU" to SKU.encodedAndHashed,
"PATCH_SOC_MANUFACTURER" to SOC_MANUFACTURER.encodedAndHashed,
"PATCH_SOC_MODEL" to SOC_MODEL.encodedAndHashed,
"PATCH_TAGS" to TAGS.encodedAndHashed,
"PATCH_TYPE" to TYPE.encodedAndHashed,
"PATCH_USER" to USER.encodedAndHashed,
)
}
try {
Class.forName("android.os.Build")
// This only works on Android,
// because it uses Android APIs.
setBuildInfo()
} catch (_: ClassNotFoundException) { }
}
private fun invokeCheck() = mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstructions(
0,
"invoke-static/range { p0 .. p0 },$INTEGRATIONS_CLASS_DESCRIPTOR->check(Landroid/app/Activity;)V",
) ?: throw mainActivityOnCreateFingerprint.exception
private companion object {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/shared/checks/CheckEnvironmentPatch;"
@OptIn(ExperimentalEncodingApi::class)
private val String.encodedAndHashed
get() = MutableStringEncodedValue(
ImmutableStringEncodedValue(
Base64.encode(MessageDigest.getInstance("SHA-1")
.digest(this.toByteArray(StandardCharsets.UTF_8))),
),
)
private val Long.encoded get() = MutableLongEncodedValue(ImmutableLongEncodedValue(this))
private fun <T : MutableEncodedValue> MethodFingerprint.setClassFields(vararg fieldNameValues: Pair<String, T>) {
val fieldNameValueMap = mapOf(*fieldNameValues)
resultOrThrow().mutableClass.fields.forEach { field ->
field.initialValue = fieldNameValueMap[field.name] ?: return@forEach
}
}
}
}

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.shared.misc.checks.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object PatchInfoBuildFingerprint : MethodFingerprint(
customFingerprint = { _, classDef -> classDef.type == "Lapp/revanced/integrations/shared/checks/PatchInfo\$Build;" },
)

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.shared.misc.checks.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object PatchInfoFingerprint : MethodFingerprint(
customFingerprint = { _, classDef ->
classDef.type == "Lapp/revanced/integrations/shared/checks/PatchInfo;"
},
)

View File

@@ -18,11 +18,13 @@ import app.revanced.patches.shared.misc.gms.fingerprints.GooglePlayUtilityFinger
import app.revanced.patches.shared.misc.gms.fingerprints.ServiceCheckFingerprint
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
import com.android.tools.smali.dexlib2.util.MethodUtil
@@ -56,7 +58,7 @@ abstract class BaseGmsCoreSupportPatch(
) : BytecodePatch(
name = "GmsCore support",
description = "Allows patched Google apps to run without root and under a different package name " +
"by using GmsCore instead of Google Play Services.",
"by using GmsCore instead of Google Play Services.",
dependencies = setOf(
ChangePackageNamePatch::class,
gmsCoreSupportResourcePatch::class,
@@ -100,17 +102,33 @@ abstract class BaseGmsCoreSupportPatch(
primeMethodFingerprint?.let { transformPrimeMethod(packageName) }
// Return these methods early to prevent the app from crashing.
(earlyReturnFingerprints + ServiceCheckFingerprint + CastDynamiteModuleFingerprint).returnEarly()
earlyReturnFingerprints.returnEarly()
ServiceCheckFingerprint.returnEarly()
// Not all apps have CastDynamiteModule, so we need to check if it's present.
if (CastDynamiteModuleFingerprint.result != null) {
CastDynamiteModuleFingerprint.returnEarly()
}
// Google Play Utility is not present in all apps, so we need to check if it's present.
if (GooglePlayUtilityFingerprint.result != null) {
GooglePlayUtilityFingerprint.returnEarly()
}
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstructions(
0,
"invoke-static/range { p0 .. p0 }, Lapp/revanced/integrations/shared/GmsCoreSupport;->" +
mainActivityOnCreateFingerprint.result?.mutableMethod?.apply {
// Temporary fix for patches with an integrations patch that hook the onCreate method as well.
val setContextIndex = indexOfFirstInstruction {
val reference = getReference<MethodReference>() ?: return@indexOfFirstInstruction false
reference.toString() == "Lapp/revanced/integrations/shared/Utils;->setContext(Landroid/content/Context;)V"
}
// Add after setContext call, because this patch needs the context.
addInstructions(
if (setContextIndex < 0) 0 else setContextIndex + 1,
"invoke-static/range { p0 .. p0 }, Lapp/revanced/integrations/shared/GmsCoreSupport;->" +
"checkGmsCore(Landroid/app/Activity;)V",
) ?: throw mainActivityOnCreateFingerprint.exception
)
} ?: throw mainActivityOnCreateFingerprint.exception
// Change the vendor of GmsCore in ReVanced Integrations.
GmsCoreSupportFingerprint.result?.mutableClass?.methods

View File

@@ -101,8 +101,8 @@ abstract class BaseGmsCoreSupportResourcePatch(
"android:authorities=\"$fromPackageName" to "android:authorities=\"$packageName",
"$fromPackageName.permission.C2D_MESSAGE" to "$packageName.permission.C2D_MESSAGE",
"$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" to "$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
"com.google.android.c2dm" to "$packageName.android.c2dm",
"com.google.android.libraries.photos.api.mars" to "$packageName.android.apps.photos.api.mars",
"com.google.android.c2dm" to "$gmsCoreVendorGroupId.android.c2dm",
"com.google.android.libraries.photos.api.mars" to "$gmsCoreVendorGroupId.android.apps.photos.api.mars",
"</queries>" to "<package android:name=\"$gmsCoreVendorGroupId.android.gms\"/></queries>",
)
@@ -110,9 +110,9 @@ abstract class BaseGmsCoreSupportResourcePatch(
transformations.entries.fold(get("AndroidManifest.xml", false).readText()) { acc, (from, to) ->
acc.replace(
from,
to
to,
)
}
},
)
}

View File

@@ -62,7 +62,7 @@ object HideAdsPatch : BytecodePatch(
// Prevent verification of an HTTP header containing the user's current plan, which would contradict the previous patch.
InterceptFingerprint.resultOrThrow().let { result ->
val conditionIndex = result.scanResult.patternScanResult!!.endIndex
val conditionIndex = result.scanResult.patternScanResult!!.endIndex + 1
result.mutableMethod.addInstruction(
conditionIndex,
"return-object p1",

View File

@@ -9,14 +9,13 @@ internal object InterceptFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC.value,
parameters = listOf("L"),
opcodes = listOf(
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT
),
strings = listOf("SC-Mob-UserPlan", "Configuration"),
customFingerprint = { _, classDef ->
classDef.sourceFile == "ApiUserPlanInterceptor.java"
classDef.sourceFile == "ApiUserPlanInterceptor.java" ||
classDef.sourceFile == "ApiUserPlanInterceptor.kt"
},
)

View File

@@ -9,7 +9,7 @@ import app.revanced.patches.swissid.integritycheck.fingerprints.CheckIntegrityFi
import app.revanced.util.resultOrThrow
@Patch(
name = "Remove Google Play Integrity Integrity check",
name = "Remove Google Play Integrity check",
description = "Removes the Google Play Integrity check. With this it's possible to use SwissID on custom ROMS." +
"If the device is rooted, root permissions must be hidden from the app.",
compatiblePackages = [CompatiblePackage("com.swisssign.swissid.mobile")],

View File

@@ -97,6 +97,7 @@ object HideLayoutComponentsPatch : BytecodePatch(
SwitchPreference("revanced_hide_attributes_section"),
SwitchPreference("revanced_hide_chapters_section"),
SwitchPreference("revanced_hide_info_cards_section"),
SwitchPreference("revanced_hide_key_concepts_section"),
SwitchPreference("revanced_hide_podcast_section"),
SwitchPreference("revanced_hide_transcript_section"),
),
@@ -137,8 +138,10 @@ object HideLayoutComponentsPatch : BytecodePatch(
SwitchPreference("revanced_hide_keyword_content_search"),
TextPreference("revanced_hide_keyword_content_phrases", inputType = InputType.TEXT_MULTI_LINE),
NonInteractivePreference("revanced_hide_keyword_content_about"),
),
),
NonInteractivePreference(key = "revanced_hide_keyword_content_about_whole_words",
tag = "app.revanced.integrations.youtube.settings.preference.HtmlPreference")
)
)
)
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(

View File

@@ -38,6 +38,7 @@ object HideShortsComponentsResourcePatch : ResourcePatch() {
SwitchPreference("revanced_hide_shorts_subscribe_button"),
SwitchPreference("revanced_hide_shorts_paused_overlay_buttons"),
SwitchPreference("revanced_hide_shorts_save_sound_button"),
SwitchPreference("revanced_hide_shorts_use_this_sound_button"),
SwitchPreference("revanced_hide_shorts_shop_button"),
SwitchPreference("revanced_hide_shorts_tagged_products"),
SwitchPreference("revanced_hide_shorts_search_suggestions"),

View File

@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
@Patch(
name = "Bypass image region restrictions",
description = "Adds an option to use a different host for user avatar and channel images," +
description = "Adds an option to use a different host for user avatar and channel images " +
"and can fix missing images that are blocked in some countries.",
dependencies = [
IntegrationsPatch::class,

View File

@@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.check
import app.revanced.patches.shared.misc.checks.BaseCheckEnvironmentPatch
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.shared.fingerprints.MainActivityOnCreateFingerprint
@Suppress("unused")
object CheckEnvironmentPatch :
BaseCheckEnvironmentPatch(
mainActivityOnCreateFingerprint = MainActivityOnCreateFingerprint,
integrationsPatch = IntegrationsPatch,
compatiblePackages = setOf(CompatiblePackage("com.google.android.youtube")),
)

View File

@@ -0,0 +1,69 @@
package app.revanced.patches.youtube.misc.dns
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.misc.resources.AddResourcesPatch
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.shared.fingerprints.MainActivityOnCreateFingerprint
import app.revanced.util.resultOrThrow
@Patch(
name = "Check watch history domain name resolution",
description = "Checks if the device DNS server is preventing user watch history from being saved.",
dependencies = [IntegrationsPatch::class],
compatiblePackages = [
CompatiblePackage(
"com.google.android.youtube",
[
"18.32.39",
"18.37.36",
"18.38.44",
"18.43.45",
"18.44.41",
"18.45.43",
"18.48.39",
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.36",
"19.04.38",
"19.05.36",
"19.06.39",
"19.07.40",
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
)
@Suppress("unused")
internal object CheckWatchHistoryDomainNameResolutionPatch : BytecodePatch(
setOf(MainActivityOnCreateFingerprint),
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/CheckWatchHistoryDomainNameResolutionPatch;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
MainActivityOnCreateFingerprint.resultOrThrow().mutableMethod.addInstructions(
// FIXME: Insert index must be greater than the insert index used by GmsCoreSupport,
// as both patch the same method and GmsCoreSupport check should be first,
// but the patch does not depend on GmsCoreSupport, so it should not be possible to enforce this
// unless a third patch is added that this patch and GmsCoreSupport depend on to manage
// the order of the patches.
1,
"invoke-static/range { p0 .. p0 }, $INTEGRATIONS_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V",
)
}
}

View File

@@ -1,385 +1,11 @@
package app.revanced.patches.youtube.misc.fix.playback
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.AddResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
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.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
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
@Patch(
name = "Spoof client",
description = "Spoofs the client to allow video playback.",
dependencies = [
SettingsPatch::class,
AddResourcesPatch::class,
UserAgentClientSpoofPatch::class,
],
compatiblePackages = [
CompatiblePackage(
"com.google.android.youtube",
[
"18.37.36",
"18.38.44",
"18.43.45",
"18.44.41",
"18.45.43",
"18.48.39",
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.36",
"19.04.38",
"19.05.36",
"19.06.39",
"19.07.40",
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
)
@Deprecated("This patch is obsolete.", replaceWith = ReplaceWith("SpoofVideoStreamsPatch"))
object SpoofClientPatch : BytecodePatch(
setOf(
// Client type spoof.
BuildInitPlaybackRequestFingerprint,
BuildPlayerRequestURIFingerprint,
SetPlayerRequestClientTypeFingerprint,
CreatePlayerRequestBodyFingerprint,
CreatePlayerRequestBodyWithModelFingerprint,
CreatePlayerRequestBodyWithVersionReleaseFingerprint,
// Player gesture config.
PlayerGestureConfigSyntheticFingerprint,
// Player speed menu item.
CreatePlaybackSpeedMenuItemFingerprint,
// Video qualities missing.
BuildRequestFingerprint,
// Watch history.
GetTrackingUriFingerprint,
),
dependencies = setOf(SpoofVideoStreamsPatch::class),
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofClientPatch;"
private const val CLIENT_INFO_CLASS_DESCRIPTOR =
"Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;"
private const val REQUEST_CLASS_DESCRIPTOR =
"Lorg/chromium/net/ExperimentalUrlRequest;"
private const val REQUEST_BUILDER_CLASS_DESCRIPTOR =
"Lorg/chromium/net/ExperimentalUrlRequest\$Builder;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences(
PreferenceScreen(
key = "revanced_spoof_client_screen",
sorting = PreferenceScreen.Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_spoof_client"),
SwitchPreference("revanced_spoof_client_use_ios"),
),
),
)
// region Block /initplayback requests to fall back to /get_watch requests.
BuildInitPlaybackRequestFingerprint.resultOrThrow().let {
val moveUriStringIndex = it.scanResult.patternScanResult!!.startIndex
it.mutableMethod.apply {
val targetRegister = getInstruction<OneRegisterInstruction>(moveUriStringIndex).registerA
addInstructions(
moveUriStringIndex + 1,
"""
invoke-static { v$targetRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
""",
)
}
}
// endregion
// region Block /get_watch requests to fall back to /player requests.
BuildPlayerRequestURIFingerprint.resultOrThrow().let {
val invokeToStringIndex = it.scanResult.patternScanResult!!.startIndex
it.mutableMethod.apply {
val uriRegister = getInstruction<FiveRegisterInstruction>(invokeToStringIndex).registerC
addInstructions(
invokeToStringIndex,
"""
invoke-static { v$uriRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri;
move-result-object v$uriRegister
""",
)
}
}
// endregion
// region Get field references to be used below.
val (clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField) =
SetPlayerRequestClientTypeFingerprint.resultOrThrow().let { result ->
// Field in the player request object that holds the client info object.
val clientInfoField = result.mutableMethod
.getInstructions().find { instruction ->
// requestMessage.clientInfo = clientInfoBuilder.build();
instruction.opcode == Opcode.IPUT_OBJECT &&
instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
// Client info object's client type field.
val clientInfoClientTypeField = result.mutableMethod
.getInstruction(result.scanResult.patternScanResult!!.endIndex)
.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientTypeField")
// Client info object's client version field.
val clientInfoClientVersionField = result.mutableMethod
.getInstruction(result.scanResult.stringsScanResult!!.matches.first().index + 1)
.getReference<FieldReference>()
?: throw PatchException("Could not find clientInfoClientVersionField")
Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
}
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
val getClientModelIndex =
CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
// The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) {
opcode == Opcode.IPUT_OBJECT
}
it.mutableMethod.getInstruction(index).getReference<FieldReference>()
?: throw PatchException("Could not find clientInfoClientModelField")
}
val clientInfoOsVersionField = CreatePlayerRequestBodyWithVersionReleaseFingerprint.resultOrThrow().let {
val getOsVersionIndex =
CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction(it.method)
// The next IPUT_OBJECT instruction after getting the client os version is setting the client os version field.
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getOsVersionIndex) {
opcode == Opcode.IPUT_OBJECT
}
it.mutableMethod.getInstruction(index).getReference<FieldReference>()
?: throw PatchException("Could not find clientInfoOsVersionField")
}
// endregion
// region Spoof client type for /player requests.
CreatePlayerRequestBodyFingerprint.resultOrThrow().let { result ->
val setClientInfoMethodName = "patch_setClientInfo"
val checkCastIndex = result.scanResult.patternScanResult!!.startIndex
var clientInfoContainerClassName: String
result.mutableMethod.apply {
val checkCastInstruction = getInstruction<OneRegisterInstruction>(checkCastIndex)
val requestMessageInstanceRegister = checkCastInstruction.registerA
clientInfoContainerClassName = checkCastInstruction.getReference<TypeReference>()!!.type
addInstruction(
checkCastIndex + 1,
"invoke-static { v$requestMessageInstanceRegister }," +
" ${result.classDef.type}->$setClientInfoMethodName($clientInfoContainerClassName)V",
)
}
// Change client info to use the spoofed values.
// Do this in a helper method, to remove the need of picking out multiple free registers from the hooked code.
result.mutableClass.methods.add(
ImmutableMethod(
result.mutableClass.type,
setClientInfoMethodName,
listOf(ImmutableMethodParameter(clientInfoContainerClassName, null, "clientInfoContainer")),
"V",
AccessFlags.PRIVATE or AccessFlags.STATIC,
null,
null,
MutableMethodImplementation(3),
).toMutable().apply {
addInstructions(
"""
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isClientSpoofingEnabled()Z
move-result v0
if-eqz v0, :disabled
iget-object v0, p0, $clientInfoField
# Set client type to the spoofed value.
iget v1, v0, $clientInfoClientTypeField
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientTypeId(I)I
move-result v1
iput v1, v0, $clientInfoClientTypeField
# Set client model to the spoofed value.
iget-object v1, v0, $clientInfoClientModelField
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientModel(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
iput-object v1, v0, $clientInfoClientModelField
# Set client version to the spoofed value.
iget-object v1, v0, $clientInfoClientVersionField
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
iput-object v1, v0, $clientInfoClientVersionField
# Set client os version to the spoofed value.
iget-object v1, v0, $clientInfoOsVersionField
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getOsVersion(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
iput-object v1, v0, $clientInfoOsVersionField
:disabled
return-void
""",
)
},
)
}
// endregion
// region Fix player gesture if spoofing to iOS.
PlayerGestureConfigSyntheticFingerprint.resultOrThrow().let {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val downAndOutLandscapeAllowedIndex = endIndex - 3
val downAndOutPortraitAllowedIndex = endIndex - 9
arrayOf(
downAndOutLandscapeAllowedIndex,
downAndOutPortraitAllowedIndex,
).forEach { index ->
val gestureAllowedMethod = context.toMethodWalker(it.mutableMethod)
.nextMethod(index, true)
.getMethod() as MutableMethod
gestureAllowedMethod.apply {
val isAllowedIndex = getInstructions().lastIndex
val isAllowed = getInstruction<OneRegisterInstruction>(isAllowedIndex).registerA
addInstructions(
isAllowedIndex,
"""
invoke-static { v$isAllowed }, $INTEGRATIONS_CLASS_DESCRIPTOR->enablePlayerGesture(Z)Z
move-result v$isAllowed
""",
)
}
}
}
// endregion
// Fix playback speed menu item if spoofing to iOS.
CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let {
val scanResult = it.scanResult.patternScanResult!!
if (scanResult.startIndex != 0) throw PatchException("Unexpected start index: ${scanResult.startIndex}")
it.mutableMethod.apply {
// Find the conditional check if the playback speed menu item is not created.
val shouldCreateMenuIndex =
indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
addInstructions(
shouldCreateMenuIndex,
"""
invoke-static { v$shouldCreateMenuRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceCreatePlaybackSpeedMenu(Z)Z
move-result v$shouldCreateMenuRegister
""",
)
}
}
// endregion
// Fix watch history if spoofing to iOS.
GetTrackingUriFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val returnUrlIndex = it.scanResult.patternScanResult!!.endIndex
val urlRegister = getInstruction<OneRegisterInstruction>(returnUrlIndex).registerA
addInstructions(
returnUrlIndex,
"""
invoke-static { v$urlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideTrackingUrl(Landroid/net/Uri;)Landroid/net/Uri;
move-result-object v$urlRegister
"""
)
}
}
// endregion
// region Fix video qualities missing, if spoofing to iOS by overriding the user agent.
BuildRequestFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
val buildRequestIndex = getInstructions().lastIndex - 2
val requestBuilderRegister = getInstruction<FiveRegisterInstruction>(buildRequestIndex).registerC
val newRequestBuilderIndex = result.scanResult.patternScanResult!!.endIndex
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
// Replace "requestBuilder.build(): Request" with "overrideUserAgent(requestBuilder, url): Request".
replaceInstruction(
buildRequestIndex,
"invoke-static { v$requestBuilderRegister, v$urlRegister }, " +
"$INTEGRATIONS_CLASS_DESCRIPTOR->" +
"overrideUserAgent(${REQUEST_BUILDER_CLASS_DESCRIPTOR}Ljava/lang/String;)" +
REQUEST_CLASS_DESCRIPTOR
)
}
}
// endregion
}
}
override fun execute(context: BytecodeContext) {}
}

View File

@@ -1,239 +1,12 @@
package app.revanced.patches.youtube.misc.fix.playback
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.all.misc.resources.AddResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.util.exception
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.instruction.ReferenceInstruction
@Patch(
description = "Spoofs the signature to prevent playback issues.",
dependencies = [
SettingsPatch::class,
PlayerTypeHookPatch::class,
PlayerResponseMethodHookPatch::class,
VideoInformationPatch::class,
SpoofSignatureResourcePatch::class,
AddResourcesPatch::class,
],
)
@Deprecated("This patch will be removed in the future.")
@Deprecated("This patch is obsolete.", replaceWith = ReplaceWith("SpoofVideoStreamsPatch"))
object SpoofSignaturePatch : BytecodePatch(
setOf(
PlayerResponseModelImplGeneralFingerprint,
PlayerResponseModelImplLiveStreamFingerprint,
PlayerResponseModelImplRecommendedLevelFingerprint,
StoryboardRendererSpecFingerprint,
StoryboardRendererDecoderSpecFingerprint,
StoryboardRendererDecoderRecommendedLevelFingerprint,
StoryboardThumbnailParentFingerprint,
SpoofSignaturePatchScrubbedPreviewLayoutFingerprint,
StatsQueryParameterFingerprint,
ParamsMapPutFingerprint,
),
dependencies = setOf(SpoofVideoStreamsPatch::class),
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofSignaturePatch;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences(
PreferenceScreen(
key = "revanced_spoof_signature_verification_screen",
sorting = Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_spoof_signature_verification_enabled"),
SwitchPreference("revanced_spoof_signature_in_feed_enabled"),
SwitchPreference("revanced_spoof_storyboard"),
),
),
)
// Hook the player parameters.
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter(
"$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;",
)
// Force the seekbar time and chapters to always show up.
// This is used if the storyboard spec fetch fails, for viewing paid videos,
// or if storyboard spoofing is turned off.
StoryboardThumbnailParentFingerprint.result?.classDef?.let { classDef ->
StoryboardThumbnailFingerprint.also {
it.resolve(
context,
classDef,
)
}.result?.let {
val endIndex = it.scanResult.patternScanResult!!.endIndex
// Replace existing instruction to preserve control flow label.
// The replaced return instruction always returns false
// (it is the 'no thumbnails found' control path),
// so there is no need to pass the existing return value to integrations.
it.mutableMethod.replaceInstruction(
endIndex,
"""
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarThumbnailOverrideValue()Z
""",
)
// Since this is end of the method must replace one line then add the rest.
it.mutableMethod.addInstructions(
endIndex + 1,
"""
move-result v0
return v0
""",
)
} ?: throw StoryboardThumbnailFingerprint.exception
}
// If storyboard spoofing is turned off, then hide the empty seekbar thumbnail view.
SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.result?.apply {
val endIndex = scanResult.patternScanResult!!.endIndex
mutableMethod.apply {
val imageViewFieldName = getInstruction<ReferenceInstruction>(endIndex).reference
addInstructions(
implementation!!.instructions.lastIndex,
"""
iget-object v0, p0, $imageViewFieldName # copy imageview field to a register
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->seekbarImageViewCreated(Landroid/widget/ImageView;)V
""",
)
}
} ?: throw SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.exception
/**
* Hook StoryBoard renderer url
*/
arrayOf(
PlayerResponseModelImplGeneralFingerprint,
PlayerResponseModelImplLiveStreamFingerprint,
).forEach { fingerprint ->
fingerprint.result?.let {
it.mutableMethod.apply {
val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex
val getStoryBoardRegister =
getInstruction<OneRegisterInstruction>(getStoryBoardIndex).registerA
addInstructions(
getStoryBoardIndex,
"""
invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$getStoryBoardRegister
""",
)
}
} ?: throw fingerprint.exception
}
// Hook recommended seekbar thumbnails quality level.
StoryboardRendererDecoderRecommendedLevelFingerprint.result?.let {
val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex
val originalValueRegister = it.mutableMethod
.getInstruction<OneRegisterInstruction>(moveOriginalRecommendedValueIndex).registerA
it.mutableMethod.addInstructions(
moveOriginalRecommendedValueIndex + 1,
"""
invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I
move-result v$originalValueRegister
""",
)
} ?: throw StoryboardRendererDecoderRecommendedLevelFingerprint.exception
// Hook the recommended precise seeking thumbnails quality level.
PlayerResponseModelImplRecommendedLevelFingerprint.result?.let {
it.mutableMethod.apply {
val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex
val originalValueRegister =
getInstruction<OneRegisterInstruction>(moveOriginalRecommendedValueIndex).registerA
addInstructions(
moveOriginalRecommendedValueIndex,
"""
invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I
move-result v$originalValueRegister
""",
)
}
} ?: throw PlayerResponseModelImplRecommendedLevelFingerprint.exception
StoryboardRendererSpecFingerprint.result?.let {
it.mutableMethod.apply {
val storyBoardUrlParams = 0
addInstructionsWithLabels(
0,
"""
if-nez p$storyBoardUrlParams, :ignore
invoke-static { p$storyBoardUrlParams }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
move-result-object p$storyBoardUrlParams
""",
ExternalLabel("ignore", getInstruction(0)),
)
}
} ?: throw StoryboardRendererSpecFingerprint.exception
// Hook the seekbar thumbnail decoder and use a NULL spec for live streams.
StoryboardRendererDecoderSpecFingerprint.result?.let {
val storyBoardUrlIndex = it.scanResult.patternScanResult!!.startIndex + 1
val storyboardUrlRegister =
it.mutableMethod.getInstruction<OneRegisterInstruction>(storyBoardUrlIndex).registerA
it.mutableMethod.addInstructions(
storyBoardUrlIndex + 1,
"""
invoke-static { v$storyboardUrlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardDecoderRendererSpec(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$storyboardUrlRegister
""",
)
} ?: throw StoryboardRendererDecoderSpecFingerprint.exception
// Fix stats not being tracked.
// Due to signature spoofing "adformat" is present in query parameters made for /stats requests,
// even though, for regular videos, it should not be.
// This breaks stats tracking.
// Replace the ad parameter with the video parameter in the query parameters.
StatsQueryParameterFingerprint.result?.let {
val putMethod = ParamsMapPutFingerprint.result?.method?.toString()
?: throw ParamsMapPutFingerprint.exception
it.mutableMethod.apply {
val adParamIndex = it.scanResult.stringsScanResult!!.matches.first().index
val videoParamIndex = adParamIndex + 3
// Replace the ad parameter with the video parameter.
replaceInstruction(adParamIndex, getInstruction(videoParamIndex))
// Call paramsMap.put instead of paramsMap.putIfNotExist
// because the key is already present in the map.
val putAdParamIndex = adParamIndex + 1
val putIfKeyNotExistsInstruction = getInstruction<FiveRegisterInstruction>(putAdParamIndex)
replaceInstruction(
putAdParamIndex,
"invoke-virtual { " +
"v${putIfKeyNotExistsInstruction.registerC}, " +
"v${putIfKeyNotExistsInstruction.registerD}, " +
"v${putIfKeyNotExistsInstruction.registerE} }, " +
putMethod,
)
}
} ?: throw StatsQueryParameterFingerprint.exception
}
override fun execute(context: BytecodeContext) {}
}

View File

@@ -2,18 +2,8 @@ package app.revanced.patches.youtube.misc.fix.playback
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
@Patch(dependencies = [ResourceMappingPatch::class])
@Deprecated("This patch will be removed in the future.")
object SpoofSignatureResourcePatch : ResourcePatch() {
internal var scrubbedPreviewThumbnailResourceId: Long = -1
override fun execute(context: ResourceContext) {
scrubbedPreviewThumbnailResourceId = ResourceMappingPatch[
"id",
"thumbnail",
]
}
override fun execute(context: ResourceContext) {}
}

View File

@@ -0,0 +1,287 @@
package app.revanced.patches.youtube.misc.fix.playback
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
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.NonInteractivePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildInitPlaybackRequestFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildMediaDataSourceFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildPlayerRequestURIFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildRequestFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreateStreamingDataFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.ProtobufClassParseByteBufferFingerprint
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
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.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
@Patch(
name = "Spoof video streams",
description = "Spoofs the client video streams to allow video playback.",
dependencies = [
SettingsPatch::class,
AddResourcesPatch::class,
UserAgentClientSpoofPatch::class,
],
compatiblePackages = [
CompatiblePackage(
"com.google.android.youtube",
[
"18.37.36",
"18.38.44",
"18.43.45",
"18.44.41",
"18.45.43",
"18.48.39",
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.36",
"19.04.38",
"19.05.36",
"19.06.39",
"19.07.40",
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
)
object SpoofVideoStreamsPatch : BytecodePatch(
setOf(
BuildInitPlaybackRequestFingerprint,
BuildPlayerRequestURIFingerprint,
CreateStreamingDataFingerprint,
BuildMediaDataSourceFingerprint,
BuildRequestFingerprint,
ProtobufClassParseByteBufferFingerprint,
),
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofVideoStreamsPatch;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences(
PreferenceScreen(
key = "revanced_spoof_video_streams_screen",
sorting = PreferenceScreen.Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_spoof_video_streams"),
ListPreference(
"revanced_spoof_video_streams_client_type",
summaryKey = null,
entriesKey = "revanced_spoof_video_streams_client_type_entries",
entryValuesKey = "revanced_spoof_video_streams_client_type_entry_values",
),
SwitchPreference(
"revanced_spoof_video_streams_ios_force_avc",
tag = "app.revanced.integrations.youtube.settings.preference.ForceAVCSpoofingPreference",
),
NonInteractivePreference("revanced_spoof_video_streams_about_ios"),
NonInteractivePreference("revanced_spoof_video_streams_about_android_vr"),
),
),
)
// region Block /initplayback requests to fall back to /get_watch requests.
BuildInitPlaybackRequestFingerprint.resultOrThrow().let {
val moveUriStringIndex = it.scanResult.patternScanResult!!.startIndex
it.mutableMethod.apply {
val targetRegister = getInstruction<OneRegisterInstruction>(moveUriStringIndex).registerA
addInstructions(
moveUriStringIndex + 1,
"""
invoke-static { v$targetRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
""",
)
}
}
// endregion
// region Block /get_watch requests to fall back to /player requests.
BuildPlayerRequestURIFingerprint.resultOrThrow().let {
val invokeToStringIndex = it.scanResult.patternScanResult!!.startIndex
it.mutableMethod.apply {
val uriRegister = getInstruction<FiveRegisterInstruction>(invokeToStringIndex).registerC
addInstructions(
invokeToStringIndex,
"""
invoke-static { v$uriRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri;
move-result-object v$uriRegister
""",
)
}
}
// endregion
// region Get replacement streams at player requests.
BuildRequestFingerprint.resultOrThrow().mutableMethod.apply {
val newRequestBuilderIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "newUrlRequestBuilder"
}
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
val freeRegister = getInstruction<OneRegisterInstruction>(newRequestBuilderIndex + 1).registerA
addInstructions(
newRequestBuilderIndex,
"""
move-object v$freeRegister, p1
invoke-static { v$urlRegister, v$freeRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V
""",
)
}
// endregion
// region Replace the streaming data with the replacement streams.
CreateStreamingDataFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
val setStreamDataMethodName = "patch_setStreamingData"
val resultMethodType = result.mutableClass.type
val videoDetailsIndex = result.scanResult.patternScanResult!!.endIndex
val videoDetailsRegister = getInstruction<TwoRegisterInstruction>(videoDetailsIndex).registerA
val videoDetailsClass = getInstruction(videoDetailsIndex).getReference<FieldReference>()!!.type
addInstruction(
videoDetailsIndex + 1,
"invoke-direct { p0, v$videoDetailsRegister }, " +
"$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V",
)
val protobufClass = ProtobufClassParseByteBufferFingerprint.resultOrThrow().mutableMethod.definingClass
val setStreamingDataIndex = result.scanResult.patternScanResult!!.startIndex
val playerProtoClass = getInstruction(setStreamingDataIndex + 1)
.getReference<FieldReference>()!!.definingClass
val setStreamingDataField = getInstruction(setStreamingDataIndex).getReference<FieldReference>()
val getStreamingDataField = getInstruction(
indexOfFirstInstructionOrThrow {
opcode == Opcode.IGET_OBJECT && getReference<FieldReference>()?.definingClass == playerProtoClass
}
).getReference<FieldReference>()
// Use a helper method to avoid the need of picking out multiple free registers from the hooked code.
result.mutableClass.methods.add(
ImmutableMethod(
resultMethodType,
setStreamDataMethodName,
listOf(ImmutableMethodParameter(videoDetailsClass, null, "videoDetails")),
"V",
AccessFlags.PRIVATE or AccessFlags.FINAL,
null,
null,
MutableMethodImplementation(9),
).toMutable().apply {
addInstructionsWithLabels(
0,
"""
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isSpoofingEnabled()Z
move-result v0
if-eqz v0, :disabled
# Get video id.
iget-object v2, p1, $videoDetailsClass->c:Ljava/lang/String;
if-eqz v2, :disabled
# Get streaming data.
invoke-static { v2 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStreamingData(Ljava/lang/String;)Ljava/nio/ByteBuffer;
move-result-object v3
if-eqz v3, :disabled
# Parse streaming data.
sget-object v4, $playerProtoClass->a:$playerProtoClass
invoke-static { v4, v3 }, $protobufClass->parseFrom(${protobufClass}Ljava/nio/ByteBuffer;)$protobufClass
move-result-object v5
check-cast v5, $playerProtoClass
# Set streaming data.
iget-object v6, v5, $getStreamingDataField
if-eqz v6, :disabled
iput-object v6, p0, $setStreamingDataField
:disabled
return-void
""",
)
},
)
}
}
// endregion
// region Remove /videoplayback request body to fix playback.
// This is needed when using iOS client as streaming data source.
BuildMediaDataSourceFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val targetIndex = getInstructions().lastIndex
// Instructions are added just before the method returns,
// so there's no concern of clobbering in-use registers.
addInstructions(
targetIndex,
"""
# Field a: Stream uri.
# Field c: Http method.
# Field d: Post data.
move-object v0, p0 # method has over 15 registers and must copy p0 to a lower register.
iget-object v1, v0, $definingClass->a:Landroid/net/Uri;
iget v2, v0, $definingClass->c:I
iget-object v3, v0, $definingClass->d:[B
invoke-static { v1, v2, v3 }, $INTEGRATIONS_CLASS_DESCRIPTOR->removeVideoPlaybackPostBody(Landroid/net/Uri;I[B)[B
move-result-object v1
iput-object v1, v0, $definingClass->d:[B
""",
)
}
}
// endregion
}
}

View File

@@ -0,0 +1,22 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object BuildMediaDataSourceFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
returnType = "V",
parameters = listOf(
"Landroid/net/Uri;",
"J",
"I",
"[B",
"Ljava/util/Map;",
"J",
"J",
"Ljava/lang/String;",
"I",
"Ljava/lang/Object;"
)
)

View File

@@ -3,13 +3,34 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object BuildRequestFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
returnType = "Lorg/chromium/net/UrlRequest;",
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL
)
customFingerprint = { methodDef, _ ->
// Different targets have slightly different parameters
// Earlier targets have parameters:
//L
//Ljava/util/Map;
//[B
//L
//L
//L
//Lorg/chromium/net/UrlRequest$Callback;
// Later targets have parameters:
//L
//Ljava/util/Map;
//[B
//L
//L
//L
//Lorg/chromium/net/UrlRequest\$Callback;
//L
val parameterTypes = methodDef.parameterTypes
(parameterTypes.size == 7 || parameterTypes.size == 8)
&& parameterTypes[1] == "Ljava/util/Map;" // URL headers.
}
)

View File

@@ -1,34 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object CreatePlaybackSpeedMenuItemFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V",
opcodes = listOf(
Opcode.IGET_OBJECT, // First instruction of the method
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
null // MOVE_RESULT or MOVE_RESULT_OBJECT, Return value controls the creation of the playback speed menu item.
),
// 19.01 and earlier is missing the second parameter.
// Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures.
customFingerprint = custom@{ methodDef, _ ->
// 19.01 and earlier parameters are: "[L"
// 19.02+ parameters are "[L", "F"
val parameterTypes = methodDef.parameterTypes
val firstParameter = parameterTypes.firstOrNull()
if (firstParameter == null || !firstParameter.startsWith("[L")) {
return@custom false
}
parameterTypes.size == 1 || (parameterTypes.size == 2 && parameterTypes[1] == "F")
}
)

View File

@@ -1,15 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object CreatePlayerRequestBodyFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf("L"),
opcodes = listOf(
Opcode.CHECK_CAST,
Opcode.IGET,
Opcode.AND_INT_LIT16,
),
strings = listOf("ms"),
)

View File

@@ -1,31 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction
import app.revanced.util.containsWideLiteralInstructionValue
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionValue(1073741824) &&
indexOfBuildModelInstruction(methodDef) >= 0
},
) {
fun indexOfBuildModelInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
val reference = getReference<FieldReference>()
reference?.definingClass == "Landroid/os/Build;" &&
reference.name == "MODEL" &&
reference.type == "Ljava/lang/String;"
}
}

View File

@@ -1,31 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction
import app.revanced.util.containsWideLiteralInstructionValue
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal object CreatePlayerRequestBodyWithVersionReleaseFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionValue(1073741824) &&
indexOfBuildVersionReleaseInstruction(methodDef) >= 0
},
) {
fun indexOfBuildVersionReleaseInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
val reference = getReference<FieldReference>()
reference?.definingClass == "Landroid/os/Build\$VERSION;" &&
reference.name == "RELEASE" &&
reference.type == "Ljava/lang/String;"
}
}

View File

@@ -0,0 +1,24 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object CreateStreamingDataFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
returnType = "V",
parameters = listOf("L"),
opcodes = listOf(
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT
),
customFingerprint = { methodDef, classDef ->
classDef.fields.any { field ->
field.name == "a" && field.type.endsWith("/StreamingDataOuterClass\$StreamingData;")
}
},
)

View File

@@ -1,25 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object ParamsMapPutFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(
"Ljava/lang/String;",
"Ljava/lang/String;",
),
opcodes = listOf(
Opcode.CONST_4,
Opcode.CONST_4,
Opcode.CONST_4,
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT_RANGE,
),
)

View File

@@ -1,49 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object PlayerGestureConfigSyntheticFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Ljava/lang/Object;"),
opcodes = listOf(
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutLandscapeAllowed.
Opcode.MOVE_RESULT,
Opcode.CHECK_CAST,
Opcode.IPUT_BOOLEAN,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutPortraitAllowed.
Opcode.MOVE_RESULT,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID,
),
customFingerprint = { methodDef, classDef ->
fun indexOfDownAndOutAllowedInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" &&
reference.parameterTypes.isEmpty() &&
reference.returnType == "Z"
}
// This method is always called "a" because this kind of class always has a single method.
methodDef.name == "a" && classDef.methods.count() == 2 &&
indexOfDownAndOutAllowedInstruction(methodDef) >= 0
},
)

View File

@@ -1,24 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint(
returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
opcodes = listOf(
Opcode.RETURN_OBJECT,
Opcode.CONST_4,
Opcode.RETURN_OBJECT,
),
customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
methodDef.containsWideLiteralInstructionValue(55735497)
},
)

View File

@@ -1,24 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object PlayerResponseModelImplLiveStreamFingerprint : MethodFingerprint(
returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
opcodes = listOf(
Opcode.RETURN_OBJECT,
Opcode.CONST_4,
Opcode.RETURN_OBJECT,
),
customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
methodDef.containsWideLiteralInstructionValue(70276274)
},
)

View File

@@ -1,24 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsWideLiteralInstructionValue
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object PlayerResponseModelImplRecommendedLevelFingerprint : MethodFingerprint(
returnType = "I",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
opcodes = listOf(
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.RETURN,
),
customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false
methodDef.containsWideLiteralInstructionValue(55735497)
},
)

View File

@@ -5,17 +5,15 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object GetTrackingUriFingerprint : MethodFingerprint(
returnType = "Landroid/net/Uri;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
internal object ProtobufClassParseByteBufferFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PROTECTED or AccessFlags.STATIC,
parameters = listOf("L", "Ljava/nio/ByteBuffer;"),
returnType = "L",
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.SGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
Opcode.RETURN_OBJECT,
),
customFingerprint = { _, classDef ->
classDef.endsWith("TrackingUrlModel;")
}
)
customFingerprint = { methodDef, _ -> methodDef.name == "parseFrom" },
)

View File

@@ -1,13 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.util.patch.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object SetPlayerRequestClientTypeFingerprint : LiteralValueFingerprint(
opcodes = listOf(
Opcode.IGET,
Opcode.IPUT, // Sets ClientInfo.clientId.
),
strings = listOf("10.29"),
literalSupplier = { 134217728 }
)

View File

@@ -1,28 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patches.youtube.misc.fix.playback.SpoofSignatureResourcePatch
import app.revanced.util.patch.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object SpoofSignaturePatchScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint(
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "V",
parameters = listOf("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I", "I"),
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.IPUT_OBJECT, // preview imageview
),
// This resource is used in ~ 40 different locations, but this method has a distinct list of parameters to match to.
literalSupplier = { SpoofSignatureResourcePatch.scrubbedPreviewThumbnailResourceId },
)

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object StatsQueryParameterFingerprint : MethodFingerprint(
strings = listOf("adunit"),
)

View File

@@ -1,24 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves to the same method as [StoryboardRendererDecoderSpecFingerprint].
*/
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"),
opcodes = listOf(
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
),
strings = listOf("#-1#"),
)

View File

@@ -1,24 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint].
*/
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"),
opcodes = listOf(
Opcode.INVOKE_INTERFACE, // First instruction of the method.
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.CONST_4,
Opcode.IF_NEZ,
),
strings = listOf("#-1#"),
)

View File

@@ -1,13 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object StoryboardRendererSpecFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
returnType = "L",
parameters = listOf("Ljava/lang/String;", "J"),
strings = listOf("\\|"),
)

View File

@@ -1,24 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves using the class found in [StoryboardThumbnailParentFingerprint].
*/
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object StoryboardThumbnailFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",
parameters = listOf(),
opcodes = listOf(
Opcode.MOVE_RESULT,
Opcode.IF_GTZ,
Opcode.GOTO,
Opcode.CONST_4,
Opcode.RETURN,
Opcode.RETURN, // Last instruction of method.
),
)

View File

@@ -1,18 +0,0 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
/**
* Here lies code that creates the seekbar thumbnails.
*
* An additional change here might force the thumbnails to be created,
* or possibly a change somewhere else (maybe involving YouTube 18.23.35 class `hte`)
*/
@Deprecated("Fingerprint is obsolete and will be deleted soon")
internal object StoryboardThumbnailParentFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Landroid/graphics/Bitmap;",
strings = listOf("Storyboard regionDecoder.decodeRegion exception - "),
)

View File

@@ -16,6 +16,7 @@ import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.reques
import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.request.callback.OnResponseStartedFingerprint
import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.request.callback.OnSucceededFingerprint
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.util.alsoResolve
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -84,17 +85,14 @@ object CronetImageUrlHook : BytecodePatch(
}
override fun execute(context: BytecodeContext) {
fun MethodFingerprint.alsoResolve(fingerprint: MethodFingerprint) =
also { resolve(context, fingerprint.resultOrThrow().classDef) }.resultOrThrow()
loadImageUrlMethod = MessageDigestImageUrlFingerprint
.alsoResolve(MessageDigestImageUrlParentFingerprint).mutableMethod
.alsoResolve(context, MessageDigestImageUrlParentFingerprint).mutableMethod
loadImageSuccessCallbackMethod = OnSucceededFingerprint
.alsoResolve(OnResponseStartedFingerprint).mutableMethod
.alsoResolve(context, OnResponseStartedFingerprint).mutableMethod
loadImageErrorCallbackMethod = OnFailureFingerprint
.alsoResolve(OnResponseStartedFingerprint).mutableMethod
.alsoResolve(context, OnResponseStartedFingerprint).mutableMethod
// The URL is required for the failure callback hook, but the URL field is obfuscated.
// Add a helper get method that returns the URL field.

View File

@@ -15,6 +15,7 @@ import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
import app.revanced.patches.shared.misc.settings.preference.TextPreference
import app.revanced.patches.youtube.misc.check.CheckEnvironmentPatch
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.fingerprints.LicenseActivityOnCreateFingerprint
import app.revanced.patches.youtube.misc.settings.fingerprints.SetThemeFingerprint
@@ -30,6 +31,9 @@ import java.io.Closeable
IntegrationsPatch::class,
SettingsResourcePatch::class,
AddResourcesPatch::class,
// Currently there is no easy way to make a mandatory patch,
// so for now this is a dependent of this patch.
CheckEnvironmentPatch::class,
],
)
object SettingsPatch :

View File

@@ -28,8 +28,6 @@ object SettingsResourcePatch : BaseSettingsResourcePatch(
override fun execute(context: ResourceContext) {
super.execute(context)
AddResourcesPatch(this::class)
// Used for a fingerprint from SettingsPatch.
appearanceStringId = ResourceMappingPatch["string", "app_theme_appearance_dark"]

View File

@@ -7,12 +7,14 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.video.information.fingerprints.*
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.alsoResolve
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -45,9 +47,11 @@ object VideoInformationPatch : BytecodePatch(
)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/VideoInformation;"
private const val INTEGRATIONS_PLAYER_INTERFACE = "Lapp/revanced/integrations/youtube/patches/VideoInformation${'$'}PlaybackController;"
private lateinit var playerInitMethod: MutableMethod
private var playerInitInsertIndex = 4
private var playerInitInsertIndex = -1
private var playerInitInsertRegister = -1
private lateinit var mdxInitMethod: MutableMethod
private var mdxInitInsertIndex = -1
@@ -70,42 +74,43 @@ object VideoInformationPatch : BytecodePatch(
with(PlayerInitFingerprint.resultOrThrow()) {
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
// hook the player controller for use through integrations
// find the location of the first invoke-direct call and extract the register storing the 'this' object reference.
val initThisIndex = playerInitMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && getReference<MethodReference>()?.name == "<init>"
}
playerInitInsertRegister = playerInitMethod.getInstruction<FiveRegisterInstruction>(initThisIndex).registerC
playerInitInsertIndex = initThisIndex + 1
// Hook the player controller for use through integrations.
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
// seek method
val seekFingerprintResultMethod =
SeekFingerprint.also { it.resolve(context, classDef) }.resultOrThrow().method
SeekFingerprint.alsoResolve(context, PlayerInitFingerprint).method
val seekRelativeFingerprintResultMethod =
SeekRelativeFingerprint.alsoResolve(context, PlayerInitFingerprint).method
// create helper method
val seekHelperMethod = generateSeekMethodHelper(seekFingerprintResultMethod)
// add the seekTo method to the class for the integrations to call
mutableClass.methods.add(seekHelperMethod)
// Create integrations interface methods.
addSeekInterfaceMethods(mutableClass, seekFingerprintResultMethod, seekRelativeFingerprintResultMethod)
}
with(MdxPlayerDirectorSetVideoStageFingerprint.resultOrThrow()) {
mdxInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
// find the location of the first invoke-direct call and extract the register storing the 'this' object reference
val initThisIndex = mdxInitMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && getReference<MethodReference>()?.name == "<init>"
}
mdxInitInsertRegister = mdxInitMethod.getInstruction<FiveRegisterInstruction>(initThisIndex).registerC
mdxInitInsertIndex = initThisIndex + 1
// hook the MDX director for use through integrations
// Hook the MDX director for use through integrations.
onCreateHookMdx(INTEGRATIONS_CLASS_DESCRIPTOR, "initializeMdx")
// MDX seek method
val mdxSeekFingerprintResultMethod =
MdxSeekFingerprint.apply { resolve(context, classDef) }.resultOrThrow().method
MdxSeekFingerprint.alsoResolve(context, MdxPlayerDirectorSetVideoStageFingerprint).method
val mdxSeekRelativeFingerprintResultMethod =
MdxSeekRelativeFingerprint.alsoResolve(context, MdxPlayerDirectorSetVideoStageFingerprint).method
// create helper method
val mdxSeekHelperMethod = generateSeekMethodHelper(mdxSeekFingerprintResultMethod)
// add the seekTo method to the class for the integrations to call
mutableClass.methods.add(mdxSeekHelperMethod)
addSeekInterfaceMethods(mutableClass, mdxSeekFingerprintResultMethod, mdxSeekRelativeFingerprintResultMethod)
}
with(CreateVideoPlayerSeekbarFingerprint.result!!) {
@@ -173,33 +178,42 @@ object VideoInformationPatch : BytecodePatch(
userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
}
private fun generateSeekMethodHelper(seekMethod: Method): MutableMethod {
private fun addSeekInterfaceMethods(targetClass: MutableClass, seekToMethod: Method, seekToRelativeMethod: Method) {
// Add the interface and methods that integrations calls.
targetClass.interfaces.add(INTEGRATIONS_PLAYER_INTERFACE)
// create helper method
val generatedMethod = ImmutableMethod(
seekMethod.definingClass,
"seekTo",
listOf(ImmutableMethodParameter("J", null, "time")),
"Z",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null, null,
MutableMethodImplementation(4)
).toMutable()
arrayOf(
seekToMethod to "seekTo",
seekToRelativeMethod to "seekToRelative"
).forEach { (method, name) ->
// Add interface method.
// Get enum type for the seek helper method.
val seekSourceEnumType = method.parameterTypes[1].toString()
// get enum type for the seek helper method
val seekSourceEnumType = seekMethod.parameterTypes[1].toString()
val interfaceImplementation = ImmutableMethod(
targetClass.type,
name,
listOf(ImmutableMethodParameter("J", null, "time")),
"Z",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null, null,
MutableMethodImplementation(4)
).toMutable()
// insert helper method instructions
generatedMethod.addInstructions(
0,
"""
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
invoke-virtual { p0, p1, p2, v0 }, $seekMethod
move-result p1
return p1
"""
)
return generatedMethod
// Insert helper method instructions.
interfaceImplementation.addInstructions(
0,
"""
# first enum (field a) is SEEK_SOURCE_UNKNOWN
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
invoke-virtual { p0, p1, p2, v0 }, $method
move-result p1
return p1
"""
)
targetClass.methods.add(interfaceImplementation)
}
}
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
@@ -220,8 +234,8 @@ object VideoInformationPatch : BytecodePatch(
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
playerInitMethod.insert(
playerInitInsertIndex++,
"v0",
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
"v$playerInitInsertRegister",
"$targetMethodClass->$targetMethodName($INTEGRATIONS_PLAYER_INTERFACE)V"
)
/**
@@ -234,7 +248,7 @@ object VideoInformationPatch : BytecodePatch(
mdxInitMethod.insert(
mdxInitInsertIndex++,
"v$mdxInitInsertRegister",
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
"$targetMethodClass->$targetMethodName($INTEGRATIONS_PLAYER_INTERFACE)V"
)
/**

View File

@@ -5,6 +5,9 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves using class found in [MdxPlayerDirectorSetVideoStageFingerprint].
*/
internal object MdxSeekFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",

View File

@@ -0,0 +1,19 @@
package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves using class found in [MdxPlayerDirectorSetVideoStageFingerprint].
*/
internal object MdxSeekRelativeFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",
parameters = listOf("J", "L"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE
)
)

View File

@@ -3,6 +3,9 @@ package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
/**
* Resolves using class found in [PlayerInitFingerprint].
*/
internal object SeekFingerprint : MethodFingerprint(
strings = listOf("Attempting to seek during an ad")
)

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
/**
* Resolves using class found in [PlayerInitFingerprint].
*/
internal object SeekRelativeFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",
parameters = listOf("J", "L"),
opcodes = listOf(
Opcode.ADD_LONG_2ADDR,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.RETURN
)
)

View File

@@ -249,3 +249,9 @@ fun Iterable<MethodFingerprint>.returnEarly(bool: Boolean = false) = forEach { f
fun List<MethodFingerprint>.returnEarly(bool: Boolean = false) = forEach { fingerprint ->
fingerprint.returnEarly(bool)
}
/**
* Resolves this fingerprint using the classDef of a parent fingerprint.
*/
fun MethodFingerprint.alsoResolve(context: BytecodeContext, parentFingerprint: MethodFingerprint) =
also { resolve(context, parentFingerprint.resultOrThrow().classDef) }.resultOrThrow()

View File

@@ -32,15 +32,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<!-- Settings about dialog. -->
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
@@ -57,7 +58,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<!-- '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.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- 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">
@@ -171,8 +172,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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. -->
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
@@ -206,6 +205,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">

View File

@@ -32,15 +32,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<!-- Settings about dialog. -->
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
@@ -57,7 +58,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<!-- '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.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- 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">
@@ -171,8 +172,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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. -->
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
@@ -206,6 +205,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">

View File

@@ -32,6 +32,17 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
<string name="revanced_check_environment_failed_title">ŲØ´Ų„ØĒ ØšŲ…Ų„ŲŠØ§ØĒ Ø§Ų„ØĒØ­Ų‚Ų‚</string>
<string name="revanced_check_environment_dialog_open_official_source_button">؁ØĒØ­ Ø§Ų„Ų…ŲˆŲ‚Øš Ø§Ų„ØąØŗŲ…ŲŠ</string>
<string name="revanced_check_environment_dialog_ignore_button">ØĒØŦØ§Ų‡Ų„</string>
<string name="revanced_check_environment_failed_message">&lt;h5&gt;Ų„Ø§ ŲŠØ¨Ø¯Ųˆ ØŖŲ† Ų‡Ø°Ø§ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚ Ų‚Ø¯ ØĒŲ… ØĒØšØ¯ŲŠŲ„Ų‡ Ų…Ų† Ų‚Ø¨Ų„Ųƒ.&lt;/h5&gt;&lt;br&gt;Ų‚Ø¯ Ų„Ø§ ŲŠØšŲ…Ų„ Ų‡Ø°Ø§ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚ Ø¨Ø´ŲƒŲ„ ØĩØ­ŲŠØ­ØŒ &lt;b&gt;Ų‚Ø¯ ŲŠŲƒŲˆŲ† ØļØ§ØąŲ‹Ø§ ØŖŲˆ Ø­ØĒŲ‰ ØŽØˇŲŠØąŲ‹Ø§ Ų„Ų„Ø§ØŗØĒØŽØ¯Ø§Ų…&lt;/b&gt;.&lt;br&gt;&lt;br&gt;ØĒØ´ŲŠØą Ų‡Ø°Ų‡ Ø§Ų„ŲØ­ŲˆØĩاØĒ ØĨŲ„Ų‰ ØŖŲ† Ų‡Ø°Ø§ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚ ØĒŲ… ØĒØšØ¯ŲŠŲ„Ų‡ Ų…ØŗØ¨Ų‚Ų‹Ø§ ØŖŲˆ ØĒŲ… Ø§Ų„Ø­ØĩŲˆŲ„ ØšŲ„ŲŠŲ‡ Ų…Ų† Ø´ØŽØĩ ØĸØŽØą:&lt;br&gt;&lt;br&gt;&lt;small&gt;%1$s&lt;/small&gt;&lt;br&gt;؊؈ØĩŲ‰ بشد؊ Ø¨Ų€ &lt;b&gt;ØĨŲ„ØēØ§ØĄ ØĒØĢØ¨ŲŠØĒ Ų‡Ø°Ø§ Ø§Ų„ØĒØˇØ¨ŲŠŲ‚ ؈ØĒØšØ¯ŲŠŲ„Ų‡ Ø¨Ų†ŲØŗŲƒ&lt;/b&gt; Ų„Ų„ØĒØŖŲƒØ¯ Ų…Ų† ØŖŲ†Ųƒ ØĒØŗØĒØŽØ¯Ų… ØĒØˇØ¨ŲŠŲ‚Ų‹Ø§ Ų…ØšØĒŲ…Ø¯Ų‹Ø§ ؈ØĸŲ…Ų†Ų‹Ø§.&lt;p&gt;&lt;br&gt;؁؊ Ø­Ø§Ų„ØŠ ØĒØŦØ§Ų‡Ų„ Ų‡Ø°Ø§ Ø§Ų„ØĒØ­Ø°ŲŠØąØŒ ØŗŲŠØĒŲ… ØšØąØļŲ‡ Ų…ØąØĒŲŠŲ† ŲŲ‚Øˇ.</string>
<string name="revanced_check_environment_not_same_patching_device">ØĒŲ… ØĒØšØ¯ŲŠŲ„Ų‡ ØšŲ„Ų‰ ØŦŲ‡Ø§Ø˛ Ų…ØŽØĒ؄؁</string>
<string name="revanced_check_environment_manager_not_expected_installer">Ų„Ų… ؊ØĒŲ… ØĒØĢØ¨ŲŠØĒŲ‡ Ø¨ŲˆØ§ØŗØˇØŠ ReVanced Manager</string>
<string name="revanced_check_environment_not_near_patch_time">ØĒŲ… ØĒØšØ¯ŲŠŲ„Ų‡ Ų‚Ø¨Ų„ ØŖŲƒØĢØą Ų…Ų† 10 Ø¯Ų‚Ø§ØĻŲ‚</string>
<string name="revanced_check_environment_not_near_patch_time_days">ØĒŲ… Ø§Ų„ØĒØšØ¯ŲŠŲ„ Ų…Ų†Ø° %s ŲŠŲˆŲ…</string>
<string name="revanced_check_environment_not_near_patch_time_invalid">ØĒØ§ØąŲŠØŽ ØĨŲ†Ø´Ø§ØĄ APK ØĒØ§Ų„Ų</string>
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_confirm_user_dialog_title">Ų‡Ų„ ØĒØąØēب ؁؊ Ø§Ų„Ų…ØĒابؚ؊؟</string>
<string name="revanced_settings_reset">ØĨؚاد؊ Ø§Ų„ØĒØšŲŠŲŠŲ†</string>
@@ -42,6 +53,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_settings_import_reset">ØĨؚاد؊ ØĒØšŲŠŲŠŲ† ØĨؚداداØĒ ReVanced ØĨŲ„Ų‰ Ø§Ų„ŲˆØļØš Ø§Ų„Ø§ŲØĒØąØ§Øļ؊</string>
<string name="revanced_settings_import_success">ØĒŲ… Ø§ØŗØĒŲŠØąØ§Ø¯ %d ØĨؚداداØĒ</string>
<string name="revanced_settings_import_failure_parse">ŲØ´Ų„ Ø§Ų„Ø§ØŗØĒŲŠØąØ§Ø¯: %s</string>
<string name="revanced_pref_import_export_title">Ø§ØŗØĒŲŠØąØ§Ø¯ / ØĒØĩØ¯ŲŠØą</string>
<string name="revanced_pref_import_export_summary">Ø§ØŗØĒŲŠØąØ§Ø¯ / ØĒØĩØ¯ŲŠØą ØĨؚداداØĒ ReVanced</string>
<!-- Settings about dialog. -->
<string name="revanced_settings_about_links_body">ØŖŲ†ØĒ ØĒØŗØĒØŽØ¯Ų… ØĨØĩØ¯Ø§Øą ReVanced Patches &lt;i&gt;%s&lt;/i&gt;</string>
<string name="revanced_settings_about_links_dev_header">Ų…Ų„Ø§Ø­Ø¸ØŠ</string>
<string name="revanced_settings_about_links_dev_body">Ų‡Ø°Ø§ Ø§Ų„ØĨØĩØ¯Ø§Øą Ų‡Ųˆ ØĨØĩØ¯Ø§Øą Ų…ØŗØ¨Ų‚ØŒ ŲˆŲ‚Ø¯ ØĒŲˆØ§ØŦŲ‡ Ų…Ø´Ø§ŲƒŲ„ ØēŲŠØą Ų…ØĒŲˆŲ‚ØšØŠ</string>
<string name="revanced_settings_about_links_header">Ø§Ų„ØąŲˆØ§Ø¨Øˇ Ø§Ų„ØąØŗŲ…ŲŠØŠ</string>
<string name="revanced_settings_about_links_donate">ØĒØ¨ØąØš</string>
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
@@ -54,14 +73,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
<string name="revanced_settings_about_links_body">ØŖŲ†ØĒ ØĒØŗØĒØŽØ¯Ų… ØĨØĩØ¯Ø§Øą ReVanced Patches &lt;i&gt;%s&lt;/i&gt;</string>
<string name="revanced_settings_about_links_dev_header">Ų…Ų„Ø§Ø­Ø¸ØŠ</string>
<string name="revanced_settings_about_links_dev_body">Ų‡Ø°Ø§ Ø§Ų„ØĨØĩØ¯Ø§Øą Ų‡Ųˆ ØĨØĩØ¯Ø§Øą Ų…ØŗØ¨Ų‚ØŒ ŲˆŲ‚Ø¯ ØĒŲˆØ§ØŦŲ‡ Ų…Ø´Ø§ŲƒŲ„ ØēŲŠØą Ų…ØĒŲˆŲ‚ØšØŠ</string>
<string name="revanced_settings_about_links_header">Ø§Ų„ØąŲˆØ§Ø¨Øˇ Ø§Ų„ØąØŗŲ…ŲŠØŠ</string>
<string name="revanced_pref_import_export_title">Ø§ØŗØĒŲŠØąØ§Ø¯ / ØĒØĩØ¯ŲŠØą</string>
<string name="revanced_pref_import_export_summary">Ø§ØŗØĒŲŠØąØ§Ø¯ / ØĒØĩØ¯ŲŠØą ØĨؚداداØĒ ReVanced</string>
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">Ų„Ų…Ø­ØŠ</string>
<string name="revanced_settings_screen_01_ads_title">Ø§Ų„ØĨØšŲ„Ø§Ų†Ø§ØĒ</string>
@@ -211,6 +222,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_info_cards_section_title">ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„Ų…ØšŲ„ŲˆŲ…Ø§ØĒ</string>
<string name="revanced_hide_info_cards_section_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„Ų…ØšŲ„ŲˆŲ…Ø§ØĒ</string>
<string name="revanced_hide_info_cards_section_summary_off">؊ØĒŲ… ØšØąØļ Ų‚ØŗŲ… Ø¨ØˇØ§Ų‚Ø§ØĒ Ø§Ų„Ų…ØšŲ„ŲˆŲ…Ø§ØĒ</string>
<string name="revanced_hide_key_concepts_section_title">ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… \'Ø§Ų„Ų…ŲØ§Ų‡ŲŠŲ… Ø§Ų„ØŖØŗØ§ØŗŲŠØŠ\'</string>
<string name="revanced_hide_key_concepts_section_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… \'Ø§Ų„Ų…ŲØ§Ų‡ŲŠŲ… Ø§Ų„ØŖØŗØ§ØŗŲŠØŠ\'</string>
<string name="revanced_hide_key_concepts_section_summary_off">؊ØĒŲ… ØšØąØļ Ų‚ØŗŲ… \'Ø§Ų„Ų…ŲØ§Ų‡ŲŠŲ… Ø§Ų„ØŖØŗØ§ØŗŲŠØŠ\'</string>
<string name="revanced_hide_transcript_section_title">ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… Ø§Ų„Ų†Øĩ</string>
<string name="revanced_hide_transcript_section_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ų‚ØŗŲ… Ø§Ų„Ų†Øĩ</string>
<string name="revanced_hide_transcript_section_summary_off">؊ØĒŲ… ØšØąØļ Ų‚ØŗŲ… Ø§Ų„Ų†Øĩ</string>
@@ -239,14 +253,18 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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.
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">Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ ŲˆØ§Ų„ØšØ¨Ø§ØąØ§ØĒ Ø§Ų„Ų…ØąØ§Ø¯ ØĨØŽŲØ§Ø¤Ų‡Ø§ØŒ ؅؁ØĩŲˆŲ„ØŠ Ø¨ØŖØŗØˇØą ØŦØ¯ŲŠØ¯\n\nØ§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„ØĒ؊ ØĒØ­ØĒ؈؊ ØšŲ„Ų‰ ØŖØ­ØąŲ ŲƒØ¨ŲŠØąØŠ ؁؊ Ø§Ų„ŲˆØŗØˇ ؊ØŦب ØĨØ¯ØŽØ§Ų„Ų‡Ø§ Ų…Øš Ø§Ų„ØĒØēŲ„ŲŠŲ (Ų…ØĢŲ„: iPhone, TikTok, Leblanc)</string>
<string name="revanced_hide_keyword_content_phrases_summary">Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ ŲˆØ§Ų„ØšØ¨Ø§ØąØ§ØĒ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ Ø§Ų„ØĒ؊ ؊ØŦب ØĨØŽŲØ§Ø¤Ų‡Ø§ØŒ ؅؁ØĩŲˆŲ„ØŠ Ø¨ØŗØˇØą ØŦØ¯ŲŠØ¯\n\nØ§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ ŲŠŲ…ŲƒŲ† ØŖŲ† ØĒŲƒŲˆŲ† ØŖØŗŲ…Ø§ØĄ Ų‚Ų†ŲˆØ§ØĒ ØŖŲˆ ØŖŲŠ Ų†Øĩ ŲŠØ¸Ų‡Øą ؁؊ ØšŲ†Ø§ŲˆŲŠŲ† Ø§Ų„ŲŲŠØ¯ŲŠŲˆ\n\n؊ØŦب ØĨØ¯ØŽØ§Ų„ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„ØĒ؊ ØĒØ­ØĒ؈؊ ØšŲ„Ų‰ ØŖØ­ØąŲ ŲƒØ¨ŲŠØąØŠ ؁؊ Ø§Ų„ŲˆØŗØˇ بØĨØŗØĒØŽØ¯Ø§Ų… Ø§Ų„ØŖØ­ØąŲ Ø§Ų„ŲƒØ¨ŲŠØąØŠ (Ų…ØĢØ§Ų„: iPhone، TikTok، LeBlanc)</string>
<string name="revanced_hide_keyword_content_about_title">Ø­ŲˆŲ„ ØĒØĩŲŲŠØŠ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ</string>
<string name="revanced_hide_keyword_content_about_summary">Ø§Ų„ØĩŲØ­ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ/Ø§Ų„Ø§Ø´ØĒØąØ§Ųƒ/Ų†ØĒاØĻØŦ Ø§Ų„Ø¨Ø­ØĢ ؊ØĒŲ… ØĒØĩ؁؊ØĒŲ‡Ø§ Ų„ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ø­ØĒŲˆŲ‰ Ø§Ų„Ø°ŲŠ ŲŠØˇØ§Ø¨Ų‚ ØšØ¨Ø§ØąØ§ØĒ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ\n\nØ§Ų„ØĒŲ‚ŲŠŲŠØ¯\nâ€ĸ بؚØļ Ø§Ų„Ų…Ų‚Ø§ØˇØš Ø§Ų„Ų‚ØĩŲŠØąØŠ Ų‚Ø¯ Ų„Ø§ ØĒŲƒŲˆŲ† Ų…ØŽŲŲŠØŠ\nâ€ĸ بؚØļ Ų…ŲƒŲˆŲ†Ø§ØĒ ŲˆØ§ØŦŲ‡ØŠ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ų‚Ø¯ Ų„Ø§ ØĒŲƒŲˆŲ† Ų…ØŽŲŲŠØŠ\nâ€ĸ Ø§Ų„Ø¨Ø­ØĢ ØšŲ† ŲƒŲ„Ų…ØŠ ØąØĻŲŠØŗŲŠØŠ Ų‚Ø¯ Ų„Ø§ ŲŠØ¸Ų‡Øą ØŖŲŠ Ų†ØĒاØĻØŦ</string>
<string name="revanced_hide_keyword_content_about_summary">Ø§Ų„ØĩŲØ­ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ/Ø§Ų„Ø§Ø´ØĒØąØ§ŲƒØ§ØĒ/Ų†ØĒاØĻØŦ Ø§Ų„ØĨØ´ØĒØąØ§Ųƒ/؊ØĒŲ… ØĒØĩŲŲŠØŠ Ų†ØĒاØĻØŦ Ø§Ų„Ø¨Ø­ØĢ Ų„ØĨØŽŲØ§ØĄ Ø§Ų„Ų…Ø­ØĒŲˆŲ‰ Ø§Ų„Ø°ŲŠ ؊ØĒØˇØ§Ø¨Ų‚ Ų…Øš ØšØ¨Ø§ØąØ§ØĒ Ø§Ų„ŲƒŲ„Ų…Ø§ØĒ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ\n\nØ§Ų„Ų‚ŲŠŲˆØ¯\nâ€ĸ Ų„Ø§ ŲŠŲ…ŲƒŲ† ØĨØŽŲØ§ØĄ ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts Ø¨ŲˆØ§ØŗØˇØŠ Ø§ØŗŲ… Ø§Ų„Ų‚Ų†Ø§ØŠ\nâ€ĸ Ų‚Ø¯ Ų„Ø§ ØĒŲƒŲˆŲ† بؚØļ Ų…ŲƒŲˆŲ†Ø§ØĒ ŲˆØ§ØŦŲ‡ØŠ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ų…ØŽŲŲŠØŠ\nâ€ĸ Ų‚Ø¯ Ų„Ø§ ØĒØ¸Ų‡Øą Ų†ØĒاØĻØŦ بحØĢ ØšŲ† ŲƒŲ„Ų…ØŠ ØąØĻŲŠØŗŲŠØŠ</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. -->
<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>
<!-- 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_length">Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„Ų…ŲØĒØ§Ø­ŲŠØŠ ØēŲŠØą ØĩØ§Ų„Ø­ØŠ. \'%1$s\' ØŖŲ‚Ų„ Ų…Ų† %2$d Ø­ØąŲŲ‹Ø§</string>
<string name="revanced_hide_keyword_toast_invalid_broad">Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ \'%s\' ØŗŲˆŲ ØĒØŽŲŲŠ ØŦŲ…ŲŠØš Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ</string>
<string name="revanced_hide_keyword_toast_invalid_common">Ų„Ø§ ŲŠŲ…ŲƒŲ† Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ: %s</string>
<string name="revanced_hide_keyword_toast_invalid_common_whole_word_required">ØĨØļØ§ŲØŠ Ø§Ų‚ØĒØ¨Ø§ØŗØ§ØĒ Ų„Ø§ØŗØĒØŽØ¯Ø§Ų… Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ: %s</string>
<string name="revanced_hide_keyword_toast_invalid_conflicting">Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ Ų„Ų‡Ø§ Ø¨ŲŠØ§Ų†Ø§ØĒ Ų…ØĒØļØ§ØąØ¨ØŠ: %s</string>
<string name="revanced_hide_keyword_toast_invalid_length">Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ Ų‚ØĩŲŠØąØŠ ØŦØ¯Ų‹Ø§ ؈ØĒØĒØˇŲ„Ø¨ Ø§Ų‚ØĒØ¨Ø§ØŗØ§ØĒ: %s</string>
<string name="revanced_hide_keyword_toast_invalid_broad">Ø§Ų„ŲƒŲ„Ų…ØŠ Ø§Ų„ØąØĻŲŠØŗŲŠØŠ ØŗŲˆŲ ØĒØŽŲŲŠ ØŦŲ…ŲŠØš Ø§Ų„ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ: %s</string>
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<string name="revanced_hide_general_ads_title">ØĨØŽŲØ§ØĄ Ø§Ų„ØĨØšŲ„Ø§Ų†Ø§ØĒ Ø§Ų„ØšØ§Ų…ØŠ</string>
@@ -612,6 +630,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_shorts_save_sound_button_title">ØĨØŽŲØ§ØĄ Ø­ŲØ¸ Ø§Ų„Øĩ؈ØĒ ØĨŲ„Ų‰ Ø˛Øą Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„ØĒØ´ØēŲŠŲ„</string>
<string name="revanced_hide_shorts_save_sound_button_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø­ŲØ¸ Ø§Ų„Øĩ؈ØĒ ؁؊ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„ØĒØ´ØēŲŠŲ„</string>
<string name="revanced_hide_shorts_save_sound_button_summary_off">؊ØĒŲ… ØšØąØļ Ø­ŲØ¸ Ø§Ų„Øĩ؈ØĒ ؁؊ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„ØĒØ´ØēŲŠŲ„</string>
<string name="revanced_hide_shorts_use_this_sound_button_title">ØĨØŽŲØ§ØĄ Ø§ØŗØĒØŽØ¯Ø§Ų… Ų‡Ø°Ø§ Ø§Ų„Ø˛Øą Ø§Ų„Øĩ؈ØĒ؊</string>
<string name="revanced_hide_shorts_use_this_sound_button_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø˛Øą Ø§Ų„Øĩ؈ØĒ Ų‡Ø°Ø§</string>
<string name="revanced_hide_shorts_use_this_sound_button_summary_off">Ø§ØŗØĒØŽØ¯Ų… Ų‡Ø°Ø§ Ø§Ų„Ø˛Øą Ø§Ų„Øĩ؈ØĒ؊ ŲŠØ¸Ų‡Øą</string>
<string name="revanced_hide_shorts_search_suggestions_title">ØĨØŽŲØ§ØĄ Ø§Ų‚ØĒØąØ§Ø­Ø§ØĒ Ø§Ų„Ø¨Ø­ØĢ</string>
<string name="revanced_hide_shorts_search_suggestions_summary_on">ØĒŲ… ØĨØŽŲØ§ØĄ Ø§Ų‚ØĒØąØ§Ø­Ø§ØĒ Ø§Ų„Ø¨Ø­ØĢ</string>
<string name="revanced_hide_shorts_search_suggestions_summary_off">؊ØĒŲ… ØšØąØļ Ø§Ų‚ØĒØąØ§Ø­Ø§ØĒ Ø§Ų„Ø¨Ø­ØĢ</string>
@@ -675,7 +696,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_player_overlay_opacity_invalid_toast">Ø´ŲØ§ŲŲŠØŠ ŲˆØ§ØŦŲ‡ØŠ Ø§Ų„Ų…Ø´ØēŲ„ ؊ØŦب ØŖŲ† ØĒŲƒŲˆŲ† Ø¨ŲŠŲ† 0-100</string>
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<string name="revanced_ryd_video_likes_hidden_by_video_owner">Ų…ØŽŲŲŠ</string>
<!-- 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. -->
<string name="revanced_ryd_failure_connection_timeout">Ų„Ų… ŲŠØšØŦØ¨Ų†ŲŠ ØēŲŠØą Ų…ØĒاح Ų…Ø¤Ų‚ØĒŲ‹Ø§ (Ø§Ų†ØĒŲ‡ØĒ Ų…Ų‡Ų„ØŠ API)</string>
<string name="revanced_ryd_failure_connection_status_code">Ų„Ų… ŲŠØšØŦØ¨Ų†ŲŠ ØēŲŠØą Ų…ØĒاح (Ø§Ų„Ø­Ø§Ų„ØŠ %d)</string>
@@ -771,6 +791,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_general_skipcount_sum_off">ØĒŲ… ØĒØšØˇŲŠŲ„ ØĒØĒبؚ Ų…ØąØ§ØĒ Ø§Ų„ØĒØŽØˇŲŠ</string>
<string name="revanced_sb_general_min_duration">Ø§Ų„Ø­Ø¯ Ø§Ų„ØŖØ¯Ų†Ų‰ Ų„Ų…Ø¯ØŠ Ø§Ų„Ų…Ų‚ØˇØš</string>
<string name="revanced_sb_general_min_duration_sum">Ų„Ų† ؊ØĒŲ… ØšØąØļ Ø§Ų„Ų…Ų‚Ø§ØˇØš Ø§Ų„ØŖŲ‚ØĩØą Ų…Ų† Ų‡Ø°Ų‡ Ø§Ų„Ų‚ŲŠŲ…ØŠ (Ø¨Ø§Ų„ØĢŲˆØ§Ų†ŲŠ) ØŖŲˆ ØĒØŽØˇŲŠŲ‡Ø§</string>
<string name="revanced_sb_general_min_duration_invalid">Ø§Ų„Ų…Ø¯ØŠ Ø§Ų„Ø˛Ų…Ų†ŲŠØŠ ØēŲŠØą ØĩØ§Ų„Ø­ØŠ</string>
<string name="revanced_sb_general_uuid">Ų…ØšØąŲ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ø§Ų„ŲØąŲŠØ¯ Ø§Ų„ØŽØ§Øĩ Ø¨Ųƒ</string>
<string name="revanced_sb_general_uuid_sum">؊ØŦب ØŖŲ† ŲŠØ¨Ų‚Ų‰ Ų‡Ø°Ø§ ؎اØĩŲ‹Ø§. Ø§Ų†Ų‡ Ų…ØĢŲ„ ŲƒŲ„Ų…ØŠ Ø§Ų„Ų…ØąŲˆØą ŲˆŲ„Ø§ ŲŠŲ†Ø¨Øē؊ Ų…Ø´Ø§ØąŲƒØĒŲ‡ Ų…Øš ØŖŲŠ Ø´ØŽØĩ. ØĨذا ŲƒØ§Ų† Ø´ØŽØĩ Ų…Ø§ ŲŠŲ…Ų„Ųƒ Ų‡Ø°Ø§ØŒ ŲŲŠŲ…ŲƒŲ†Ų‡ Ø§Ų†ØĒØ­Ø§Ų„ Ø´ØŽØĩ؊ØĒ؃</string>
<string name="revanced_sb_general_uuid_invalid">؊ØŦب ØŖŲ† ŲŠŲƒŲˆŲ† Ų…ØšØąŲ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ø§Ų„ØŽØ§Øĩ 30 Ø­ØąŲŲ‹Ø§ ØšŲ„Ų‰ Ø§Ų„ØŖŲ‚Ų„</string>
@@ -871,8 +892,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_new_segment_time_start">Ø§Ų„ŲˆŲ‚ØĒ Ø§Ų„Ø°ŲŠ ŲŠØ¨Ø¯ØŖ ØšŲ†Ø¯Ų‡ Ø§Ų„Ų…Ų‚ØˇØš</string>
<string name="revanced_sb_new_segment_time_end">Ø§Ų„ŲˆŲ‚ØĒ Ø§Ų„Ø°ŲŠ ŲŠŲ†ØĒŲ‡ŲŠ ØšŲ†Ø¯Ų‡ Ø§Ų„Ų…Ų‚ØˇØš</string>
<string name="revanced_sb_new_segment_confirm_title">Ų‡Ų„ Ø§Ų„ØŖŲˆŲ‚Ø§ØĒ ØĩØ­ŲŠØ­ØŠØŸ</string>
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<string name="revanced_sb_new_segment_confirm_content">Ø§Ų„Ų…Ų‚ØˇØš Ų…Ų†\n\n%1$s\nto\n%2$s\n\n(%3$s)\n\nReady to ØŦØ§Ų‡Ø˛ Ų„Ų„ØĨØąØŗØ§Ų„ØŸ</string>
<string name="revanced_sb_new_segment_start_is_before_end">؊ØŦب ØŖŲ† ØĒŲƒŲˆŲ† Ø§Ų„Ø¨Ø¯Ø§ŲŠØŠ Ų‚Ø¨Ų„ Ø§Ų„Ų†Ų‡Ø§ŲŠØŠ</string>
<string name="revanced_sb_new_segment_mark_locations_first">ØļØš ØšŲ„Ø§Ų…ØŠ ØšŲ„Ų‰ Ų…ŲˆŲ‚ØšŲŠŲ† ؁؊ Ø´ØąŲŠØˇ Ø§Ų„ŲˆŲ‚ØĒ ØŖŲˆŲ„Ų‹Ø§</string>
@@ -891,6 +910,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_stats_username_changed">ØĒŲ… ØĒØēŲŠŲŠØą Ø§ØŗŲ… Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ø¨Ų†ØŦاح</string>
<string name="revanced_sb_stats_reputation">ØŗŲ…ØšØĒ؃ Ų‡ŲŠ &lt;b&gt;%.2f&lt;/b&gt;</string>
<string name="revanced_sb_stats_submissions">Ų„Ų‚Ø¯ ØŖŲ†Ø´ØŖØĒ &lt;b&gt;%s&lt;/b&gt; Ų…Ų‚ØˇØš</string>
<string name="revanced_sb_stats_submissions_sum">اØļØēØˇ Ų‡Ų†Ø§ Ų„ØšØąØļ Ø§Ų„Ų…Ų‚Ø§ØˇØš Ø§Ų„ØŽØ§ØĩØŠ Ø¨Ųƒ</string>
<string name="revanced_sb_stats_saved_zero">Ų…ØĒØĩØ¯ØąŲŠŲ† SponsorBlock</string>
<string name="revanced_sb_stats_saved">Ų„Ų‚Ø¯ Ų‚Ų…ØĒ Ø¨Ø­ŲØ¸ Ø§Ų„Ų†Ø§Øŗ Ų…Ų† &lt;b&gt;%s&lt;/b&gt; Ų…Ų‚ØˇØš</string>
<string name="revanced_sb_stats_saved_sum_zero">اØļØēØˇ Ų‡Ų†Ø§ Ų„ØąØ¤ŲŠØŠ Ø§Ų„ØĨØ­ØĩاØĻŲŠØ§ØĒ Ø§Ų„ØšØ§Ų„Ų…ŲŠØŠ ŲˆØŖØ¨ØąØ˛ Ø§Ų„Ų…ØŗØ§Ų‡Ų…ŲŠŲ†</string>
@@ -923,7 +943,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_spoof_app_version_target_entry_2">18.20.39 - Ø§ØŗØĒؚاد؊ ØŗØąØšØŠ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ŲˆØ§ØŗØšØŠ &amp; Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„ØŦŲˆØ¯ØŠ</string>
<string name="revanced_spoof_app_version_target_entry_3">18.09.39 - Ø§ØŗØĒؚاد؊ ØšŲ„Ø§Ų…ØŠ ØĒØ¨ŲˆŲŠØ¨ Ø§Ų„Ų…ŲƒØĒب؊</string>
<string name="revanced_spoof_app_version_target_entry_4">17.41.37 - Ø§ØŗØĒؚاد؊ ØąŲ Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„ØĒØ´ØēŲŠŲ„ Ø§Ų„Ų‚Ø¯ŲŠŲ…</string>
<string name="revanced_spoof_app_version_target_entry_5">17.30.34 - Ø§ØŗØĒؚاد؊ ØĒØĩŲ…ŲŠŲ… ŲˆØ§ØŦŲ‡ØŠ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ø§Ų„Ų‚Ø¯ŲŠŲ…</string>
<string name="revanced_spoof_app_version_target_entry_5">17.33.42 - Ø§ØŗØĒؚاد؊ ØĒØĩŲ…ŲŠŲ… ŲˆØ§ØŦŲ‡ØŠ Ø§Ų„Ų…ØŗØĒØŽØ¯Ų… Ø§Ų„Ų‚Ø¯ŲŠŲ…</string>
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<string name="revanced_start_page_title">ØĒØšŲŠŲŠŲ† ØĩŲØ­ØŠ Ø§Ų„Ø¨Ø¯Ø§ŲŠØŠ</string>
@@ -1033,6 +1053,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_announcements_connection_failed">ŲØ´Ų„ Ø§Ų„Ø§ØĒØĩØ§Ų„ Ø¨Ų…ŲˆŲØą Ø§Ų„ØĨØšŲ„Ø§Ų†Ø§ØĒ</string>
<string name="revanced_announcements_dialog_dismiss">ØĒØŦØ§Ų‡Ų„</string>
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
<string name="revanced_check_watch_history_domain_name_dialog_title">ØĒØ­Ø°ŲŠØą</string>
<string name="revanced_check_watch_history_domain_name_dialog_message">Ų„Ų… ؊ØĒŲ… Ø­ŲØ¸ ØŗØŦŲ„ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ Ø§Ų„ØŽØ§Øĩ Ø¨Ųƒ.&lt;br&gt;&lt;br&gt;Ų…Ų† Ø§Ų„Ų…ØąØŦØ­ ØŖŲ† ŲŠŲƒŲˆŲ† Ø§Ų„ØŗØ¨Ø¨ ؁؊ Ø°Ų„Ųƒ Ų‡Ųˆ Ų…Ø§Ų†Øš ØĨØšŲ„Ø§Ų†Ø§ØĒ DNS ØŖŲˆ ŲˆŲƒŲŠŲ„ Ø§Ų„Ø´Ø¨ŲƒØŠ.&lt;br&gt;&lt;br&gt;Ų„ØĨØĩŲ„Ø§Ø­ Ų‡Ø°Ų‡ Ø§Ų„Ų…Ø´ŲƒŲ„ØŠØŒ Ų‚Ų… بØĨØļØ§ŲØŠ &lt;b&gt;s.youtube.com&lt;/b&gt; ØĨŲ„Ų‰ Ø§Ų„Ų‚Ø§ØĻŲ…ØŠ Ø§Ų„Ø¨ŲŠØļØ§ØĄ ØŖŲˆ Ų‚Ų… بØĨŲŠŲ‚Ø§Ų ØĒØ´ØēŲŠŲ„ ØŦŲ…ŲŠØš ØŖØ¯ŲˆØ§ØĒ Ø­Ø¸Øą DNS ŲˆŲˆŲƒŲ„Ø§ØĄ Ø§Ų„Ø¨ØąŲˆŲƒØŗŲŠ.</string>
<string name="revanced_check_watch_history_domain_name_dialog_ignore">Ų„Ø§ ØĒØšØąØļ Ų…ØąØŠ ØŖØŽØąŲ‰</string>
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
<string name="revanced_auto_repeat_title">ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØĒŲƒØąØ§Øą Ø§Ų„ØĒŲ„Ų‚Ø§ØĻ؊</string>
<string name="revanced_auto_repeat_summary_on">ØĒŲ… ØĒŲ…ŲƒŲŠŲ† Ø§Ų„ØĒŲƒØąØ§Øą Ø§Ų„ØĒŲ„Ų‚Ø§ØĻ؊</string>
@@ -1114,9 +1139,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_spoof_client_summary_on">؊ØĒŲ… Ų…Ø­Ø§ŲƒØ§ØŠ Ø§Ų„ØšŲ…ŲŠŲ„</string>
<string name="revanced_spoof_client_summary_off">Ų„Ø§ ؊ØĒŲ… Ų…Ø­Ø§ŲƒØ§ØŠ Ø§Ų„ØšŲ…ŲŠŲ„\n\nŲ‚Ø¯ Ų„Ø§ ŲŠØšŲ…Ų„ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ</string>
<string name="revanced_spoof_client_user_dialog_message">ØĨŲŠŲ‚Ø§Ų ØĒØ´ØēŲŠŲ„ Ų‡Ø°Ø§ Ø§Ų„ØĨؚداد Ų‚Ø¯ ŲŠØŗØ¨Ø¨ Ų…Ø´Ø§ŲƒŲ„ ؁؊ ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ.</string>
<string name="revanced_spoof_client_use_ios_title">Spoof Client to iOS</string>
<string name="revanced_spoof_client_use_ios_summary_on">Ø§Ų„ØšŲ…ŲŠŲ„ Ų…ØąØŗŲ„ Ø­Ø§Ų„ŲŠØ§Ų‹ ØĨŲ„Ų‰ iOS\n\nØ§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ ØĒØ´Ų…Ų„:\nâ€ĸ Ų„Ø§ ؊؈ØŦد HDR ŲŲŠØ¯ŲŠŲˆ\nâ€ĸ Ų‚Ø¯ ØĒŲƒŲˆŲ† ØŦŲˆØ¯ØŠ ŲŲŠØ¯ŲŠŲˆ ØŖØšŲ„Ų‰ Ų…ŲŲ‚ŲˆØ¯ØŠ\nâ€ĸ Ų„Ø§ ŲŠŲ…ŲƒŲ† ØĒØ´ØēŲŠŲ„ Ø§Ų„Ø¨ØĢ Ø§Ų„Ų…Ø¨Ø§Ø´Øą Ų„Ų„Øĩ؈ØĒ ŲŲ‚Øˇ</string>
<string name="revanced_spoof_client_use_ios_summary_off">Ø§Ų„ØšŲ…ŲŠŲ„ Ų…ØšØˇŲˆØ¨ Ø­Ø§Ų„ŲŠØ§Ų‹ ØĨŲ„Ų‰ ØŖŲ†Ø¯ØąŲˆŲŠØ¯ VR\n\nØ§Ų„ØĸØĢØ§Øą Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ ØĒØ´Ų…Ų„:\nâ€ĸ Ų„Ø§ ؊؈ØŦد ŲŲŠØ¯ŲŠŲˆ HDR\nâ€ĸ ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Ø§Ų„ØŖØˇŲØ§Ų„ Ų„Ø§ ؊ØĒŲ… ØĒØ´ØēŲŠŲ„Ų‡Ų…\nâ€ĸ Ų…Ų‚Ø§ØˇØš Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ŲˆŲ‚ŲˆŲØŠ ŲŠŲ…ŲƒŲ† ØŖŲ† ØĒØŗØĒØŖŲ†Ų ØšØ´ŲˆØ§ØĻŲŠØ§Ų‹\nâ€ĸ ØŦŲˆØ¯ØŠ Ų…Ų†ØŽŲØļØŠ Ų„ØĩŲˆØą Ų…ØĩØēØąØŠ Ø´ØąŲŠØˇ Ø§Ų„Ø¨Ø­ØĢ\nâ€ĸ Ø˛Øą Ø§Ų„ØĒØ­Ų…ŲŠŲ„ Ų…ØŽŲŲŠ\nâ€ĸ Ø¨ØˇØ§Ų‚Ø§ØĒ ØĨŲ†Ų‡Ø§ØĄ Ø§Ų„Ø´Ø§Ø´ØŠ Ų…ØŽŲŲŠØŠ</string>
<string name="revanced_spoof_client_type_title">Ų†ŲˆØš Spoof Client</string>
<string name="revanced_spoof_client_ios_force_avc_title">ŲØąØļ AVC iOS (H.264)</string>
<string name="revanced_spoof_client_ios_force_avc_summary_on">ØĒØąŲ…ŲŠØ˛ ŲŲŠØ¯ŲŠŲˆ iOS Ų‡Ųˆ AVC</string>
<string name="revanced_spoof_client_ios_force_avc_summary_off">ØĒØąŲ…ŲŠØ˛ ŲŲŠØ¯ŲŠŲˆ iOS Ų‡Ųˆ AVC ØŖŲˆ VP9 ØŖŲˆ AV1</string>
<string name="revanced_spoof_client_ios_force_avc_user_dialog_message">Ų‚Ø¯ ŲŠØ¤Ø¯ŲŠ ØĒŲ…ŲƒŲŠŲ† Ų‡Ø°Ø§ ØĨŲ„Ų‰ ØĒØ­ØŗŲŠŲ† ØšŲ…Øą Ø§Ų„Ø¨ØˇØ§ØąŲŠØŠ ؈ØĨØĩŲ„Ø§Ø­ Ų…Ø´ŲƒŲ„ØŠ ØĒŲ‚ØˇŲŠØš Ø§Ų„ØĒØ´ØēŲŠŲ„.\n\n؊ØĒŲ…ØĒØš ØĒŲ†ØŗŲŠŲ‚ AVC Ø¨Ø¯Ų‚ØŠ Ų‚ØĩŲˆŲ‰ ØĒØ¨Ų„Øē 1080P، ŲˆØŗŲŠØŗØĒØŽØ¯Ų… ØĒØ´ØēŲŠŲ„ Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…Ø˛ŲŠØ¯ Ų…Ų† Ø¨ŲŠØ§Ų†Ø§ØĒ Ø§Ų„ØĨŲ†ØĒØąŲ†ØĒ Ų…Ų‚Ø§ØąŲ†ØŠŲ‹ بØĒŲ†ØŗŲŠŲ‚ VP9 ØŖŲˆ AV1.</string>
<string name="revanced_spoof_client_about_android_ios_title">Ø§Ų„ØĒØŖØĢŲŠØąØ§ØĒ Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų…Ø­Ø§ŲƒØ§ØŠ iOS</string>
<string name="revanced_spoof_client_about_android_ios_summary">â€ĸ HDR Ų…Ø¯ØšŲˆŲ… ŲŲ‚Øˇ Ų…Øš ØĒØąŲ…ŲŠØ˛ AV1\nâ€ĸ ØŗØŦŲ„ Ø§Ų„Ų…Ø´Ø§Ų‡Ø¯ØŠ Ų„Ø§ ŲŠØšŲ…Ų„ Ų…Øš Ø­ØŗØ§Ø¨ Ø§Ų„ØšŲ„Ø§Ų…ØŠ Ø§Ų„ØĒØŦØ§ØąŲŠØŠ</string>
<string name="revanced_spoof_client_about_android_vr_title">Ø§Ų„ØĒØŖØĢŲŠØąØ§ØĒ Ø§Ų„ØŦØ§Ų†Ø¨ŲŠØŠ Ų„Ų…Ø­Ø§ŲƒØ§ØŠ Android VR</string>
<string name="revanced_spoof_client_about_android_vr_summary">â€ĸ Ų„Ø§ ؊؈ØŦد ŲŲŠØ¯ŲŠŲˆ HDR\nâ€ĸ Ų„Ø§ ؊ØĒŲ… ØĒØ´ØēŲŠŲ„ Ų…Ų‚Ø§ØˇØš ŲŲŠØ¯ŲŠŲˆ Ø§Ų„ØŖØˇŲØ§Ų„\nâ€ĸ ŲŠŲ…ŲƒŲ† Ø§ØŗØĒØĻŲ†Ø§Ų Ų…Ų‚Ø§ØˇØš Ø§Ų„ŲŲŠØ¯ŲŠŲˆ Ø§Ų„Ų…ØĒŲˆŲ‚ŲØŠ Ų…Ø¤Ų‚ØĒŲ‹Ø§ Ø¨Ø´ŲƒŲ„ ØšØ´ŲˆØ§ØĻ؊\nâ€ĸ Ų…ØĩØēØąØ§ØĒ Ø´ØąŲŠØˇ ØĒŲ‚Ø¯Ų… ŲŲŠØ¯ŲŠŲˆŲ‡Ø§ØĒ Shorts Ų…Ų†ØŽŲØļØŠ Ø§Ų„ØŦŲˆØ¯ØŠ\nâ€ĸ Ø˛Øą ØĨØŦØąØ§ØĄ Ø§Ų„ØĒŲ†Ø˛ŲŠŲ„ Ų…ØŽŲŲŠ\nâ€ĸ Ø¨ØˇØ§Ų‚Ø§ØĒ شاش؊ Ø§Ų„Ų†Ų‡Ø§ŲŠØŠ Ų…ØŽŲŲŠØŠ</string>
<string name="revanced_spoof_client_storyboard_timeout">Ų…Ø­Ø§ŲƒØ§ØŠ Ų…ØĩØēØąØ§ØĒ Ø§Ų„ØšŲ…ŲŠŲ„ ØēŲŠØą Ų…ØĒŲˆŲØąØŠ (Ø§Ų†ØĒŲ‡ØĒ Ų…Ų‡Ų„ØŠ API)</string>
<string name="revanced_spoof_client_storyboard_io_exception">Ų…Ø­Ø§ŲƒØ§ØŠ Ų…ØĩØēØąØ§ØĒ Ø§Ų„ØšŲ…ŲŠŲ„ ØēŲŠØą Ų…ØĒŲˆŲØąØŠ Ų…Ø¤Ų‚ØĒŲ‹Ø§: %s</string>
</patch>

View File

@@ -32,15 +32,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<!-- Settings about dialog. -->
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
@@ -57,7 +58,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<!-- '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.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- 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">
@@ -171,8 +172,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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. -->
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
@@ -206,6 +205,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">

View File

@@ -32,6 +32,17 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
<string name="revanced_check_environment_failed_title">Yoxlamalar uğursuz oldu</string>
<string name="revanced_check_environment_dialog_open_official_source_button">Xidməti veb saytÄą aç</string>
<string name="revanced_check_environment_dialog_ignore_button">Yan keç</string>
<string name="revanced_check_environment_failed_message">&lt;h5&gt;Bu tətbiq sizin tərəfinizdən yamaqlanmayÄąb.&lt;/h5&gt;&lt;br&gt;Bu tətbiq dÃŧzgÃŧn işləməyə bilər, &lt;b&gt;istifadə etmək zərərli və ya hətta təhlÃŧkəli ola bilər&lt;/b&gt;.&lt;br&gt;&lt;br&gt;&lt;br&gt;Bu yoxlamalar bu tətbiqin əvvəldən yamaqlandığınÄą və ya başqasÄąndan əldə edildiyini gÃļstərir:&lt;br&gt;&lt;br&gt;&lt;small&gt;%1$s&lt;/small&gt;&lt;br&gt; &lt;br&gt;onu silməyiniz və ÃļzÃŧnÃŧz yamaqlamağınÄąz tÃļvsiyə olunur. &lt;/b&gt;təsdiqlənmiş və təhlÃŧkəsiz tətbiq istifadə etdiyinizə əmin olmaq ÃŧçÃŧn. &lt;p&gt;&lt;br&gt; İnkar edilməzsə, bu xəbərdarlÄąq yalnÄąz iki dəfə gÃļstəriləcək.</string>
<string name="revanced_check_environment_not_same_patching_device">Fərqli cihazda yamaqlanıb</string>
<string name="revanced_check_environment_manager_not_expected_installer">ReVanced Manager tərəfindən quraşdÄąrÄąlmayÄąb</string>
<string name="revanced_check_environment_not_near_patch_time">10 dəqiqədən çox əvvəl yamaqlanÄąb</string>
<string name="revanced_check_environment_not_near_patch_time_days">%s gÃŧn əvvəl yamaqlanÄąb</string>
<string name="revanced_check_environment_not_near_patch_time_invalid">APK quruluş tarixi pozulub</string>
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_confirm_user_dialog_title">Davam etmək istəyirsiniz?</string>
<string name="revanced_settings_reset">SÄąfÄąrla</string>
@@ -42,6 +53,14 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_settings_import_reset">ReVanced tənzimləmələr standarta təyin edildi</string>
<string name="revanced_settings_import_success">%d tənzimləmə idxal edildi</string>
<string name="revanced_settings_import_failure_parse">Uğursuz idxal prosesi: %s</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. -->
<string name="revanced_settings_about_links_body">ReVanced Patches &lt;i&gt;%s&lt;/i&gt; versiyasını istifadə edirsiniz</string>
<string name="revanced_settings_about_links_dev_header">Qeyd</string>
<string name="revanced_settings_about_links_dev_body">Bu versiya ilkin buraxÄąlÄąÅŸdÄąr və gÃļzlənilməz problemlərlə Ãŧzləşə bilərsiniz</string>
<string name="revanced_settings_about_links_header">Rəsmi bağlantılar</string>
<string name="revanced_settings_about_links_donate">İanə ver</string>
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
@@ -54,14 +73,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
<string name="revanced_settings_about_links_body">ReVanced Patches &lt;i&gt;%s&lt;/i&gt; versiyasını istifadə edirsiniz</string>
<string name="revanced_settings_about_links_dev_header">Qeyd</string>
<string name="revanced_settings_about_links_dev_body">Bu versiya ilkin buraxÄąlÄąÅŸdÄąr və gÃļzlənilməz problemlərlə Ãŧzləşə bilərsiniz</string>
<string name="revanced_settings_about_links_header">Rəsmi bağlantılar</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>
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">HaqqÄąnda</string>
<string name="revanced_settings_screen_01_ads_title">Reklamlar</string>
@@ -145,9 +156,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_community_posts_title">İcma elanların gizlət</string>
<string name="revanced_hide_community_posts_summary_on">İcma elanları gizlədilib</string>
<string name="revanced_hide_community_posts_summary_off">İcma elanlarÄą gÃļstərilir</string>
<string name="revanced_hide_compact_banner_title">Yığcam bannerləri gizlət</string>
<string name="revanced_hide_compact_banner_summary_on">Yığcam bannerlər gizlidir</string>
<string name="revanced_hide_compact_banner_summary_off">Yığcam bannerlər gÃļstərilir</string>
<string name="revanced_hide_compact_banner_title">Yığcam etiketləri gizlət</string>
<string name="revanced_hide_compact_banner_summary_on">Yığcam etiketlər gizlidir</string>
<string name="revanced_hide_compact_banner_summary_off">Yığcam etiketlər gÃļstərilir</string>
<string name="revanced_hide_movies_section_title">Filmlər bÃļlməsini gizlət</string>
<string name="revanced_hide_movies_section_summary_on">Filmlər bÃļlməsi gizlidir</string>
<string name="revanced_hide_movies_section_summary_off">Filmlər bÃļlməsi gÃļstərilir</string>
@@ -184,7 +195,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_related_videos_title">Cəld fəaliyyətlərdə əlaqəli videoları gizlə</string>
<string name="revanced_hide_related_videos_summary_on">Əlaqədar videolar gizlədilib</string>
<string name="revanced_hide_related_videos_summary_off">Əlaqədar videolar gÃļstərilir</string>
<string name="revanced_hide_image_shelf_title">AxtarÄąÅŸ nəticələrindəki şəkil bÃļlməsin gizlət</string>
<string name="revanced_hide_image_shelf_title">AxtarÄąÅŸ nəticəsində şəkil bÃļlməsin gizlə</string>
<string name="revanced_hide_image_shelf_summary_on">Şəkil bÃļlməsi gizlidir</string>
<string name="revanced_hide_image_shelf_summary_off">Şəkil bÃļlməsi gÃļstərilir</string>
<string name="revanced_hide_latest_posts_ads_title">Son elanları gizlət</string>
@@ -211,6 +222,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_info_cards_section_title">Məlumat kartlarÄą bÃļlməsini 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\" bÃļlməsini 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Ãļstərilir</string>
<string name="revanced_hide_transcript_section_title">Transkripsiya bÃļlməsini 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>
@@ -239,14 +253,18 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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.
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ÄąlmÄąÅŸ gizlədiləcək açar sÃļzlər və ifadələr\n\nOrtada bÃļyÃŧk hərf olan sÃļzlər korpusla birlikdə daxil edilməlidir (yəni: iPhone, TikTok, LeBlanc)</string>
<string name="revanced_hide_keyword_content_phrases_summary">Yeni sətirlərlə ayrÄąlmÄąÅŸ gizlədiləcək açar sÃļzlər və frazalar\n\nAçar sÃļzlər kanal adlarÄą və ya video adlarÄąnda gÃļstərilən istənilən mətn ola bilər\n\nOrtada bÃļyÃŧk hərf olan sÃļzlər korpusla birlikdə qeyd edilməlidir (yəni: iPhone, TikTok, LeBlanc)</string>
<string name="revanced_hide_keyword_content_about_title">Açar sÃļz filtrləməsi haqqÄąnda</string>
<string name="revanced_hide_keyword_content_about_summary">Əsas səhifə/Abunəlik/AxtarÄąÅŸ nəticələri açar sÃļz ifadələrinə uyğunlaşan məzmunu gizlətmək ÃŧçÃŧn filtrlənir\n\nMəhdudiyyətlər\nâ€ĸ Bəzi Shorts gizlənə bilməz\nâ€ĸ Bəzi UI elementləri gizlənə bilməz\nâ€ĸ Açar sÃļz axtarÄąÅŸÄą heç bir nəticə gÃļstərməyə bilər</string>
<string name="revanced_hide_keyword_content_about_summary">Əsas səhifə/Abunəlik/AxtarÄąÅŸ nəticələri açar sÃļz ifadələrinə uyğunlaşan məzmunu gizlətmək ÃŧçÃŧn filtrlənir\n\nMəhdudiyyətlər\nâ€ĸ Shorts-lar kanal adÄąna gÃļrə gizlənə bilməz\nâ€ĸ Bəzi UI hissəcikləri gizlədilə bilməz\nâ€ĸ Açar sÃļz axtarÄąÅŸÄąnda nəticə olmaya 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. -->
<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">EtibarsÄąz açar sÃļzÃŧ. \'%s\' istifadə edilə bilməz</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_length">EtibarsÄąz açar sÃļzÃŧ. \'%1$s\', %2$d simvoldan azdÄąr</string>
<string name="revanced_hide_keyword_toast_invalid_broad">\"%s\" açar sÃļzÃŧ, bÃŧtÃŧn videolarda gizlədiləcək</string>
<string name="revanced_hide_keyword_toast_invalid_common">Açar sÃļz istifadə edilə bilmir: %s</string>
<string name="revanced_hide_keyword_toast_invalid_common_whole_word_required">Açar sÃļz istifadəsi ÃŧçÃŧn istinad əlavə et: %s</string>
<string name="revanced_hide_keyword_toast_invalid_conflicting">Açar sÃļzÃŧn ziddiyyətli hissəcikləri var: %s</string>
<string name="revanced_hide_keyword_toast_invalid_length">Açar sÃļz çox qÄąsadÄąr və istinad tələb edir: %s</string>
<string name="revanced_hide_keyword_toast_invalid_broad">Açar sÃļz, bÃŧtÃŧn videolarÄą gizlədəcək: %s</string>
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<string name="revanced_hide_general_ads_title">Ümumi reklamlarÄą gizlət</string>
@@ -264,22 +282,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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 panelin gizlət</string>
<string name="revanced_hide_products_banner_summary_on">Panel gizlədilib</string>
<string name="revanced_hide_products_banner_summary_off">Panel gÃļstərilir</string>
<string name="revanced_hide_shopping_links_title">Video aÃ§ÄąqlamadakÄą alÄąÅŸ-veriş linklərin gizlə</string>
<string name="revanced_hide_products_banner_title">Məhsullara baxma 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_shopping_links_title">Video aÃ§Äąqlama alÄąÅŸ-veriş linklər gizlə</string>
<string name="revanced_hide_shopping_links_summary_on">AlÄąÅŸ-veriş bağlantÄąlarÄą gizlədilir</string>
<string name="revanced_hide_shopping_links_summary_off">AlÄąÅŸ-veriş bağlantÄąlarÄą gÃļstərilir</string>
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<string name="revanced_hide_visit_store_button_title">KanaldakÄą \"MağazanÄą ziyarət et\" dÃŧyməsin gizlə</string>
<string name="revanced_hide_visit_store_button_title">Kanalda \"Mağaza ziyarət\" dÃŧymə gizlə</string>
<string name="revanced_hide_visit_store_button_summary_on">DÃŧymə gizlidir</string>
<string name="revanced_hide_visit_store_button_summary_off">DÃŧymə gÃļstərilir</string>
<string name="revanced_hide_web_search_results_title">Veb axtarÄąÅŸ nəticələrini gizlət</string>
<string name="revanced_hide_web_search_results_summary_on">Veb axtarÄąÅŸ nəticələri gizlədilir</string>
<string name="revanced_hide_web_search_results_summary_off">Veb axtarÄąÅŸ nəticələri gÃļstərilir</string>
<string name="revanced_hide_merchandise_banners_title">Məhsul bannerlərini gizlət</string>
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul bannerləri gizlədilir</string>
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul bannerləri gÃļstərilir</string>
<string name="revanced_hide_merchandise_banners_title">Məhsul etiketlərini gizlət</string>
<string name="revanced_hide_merchandise_banners_summary_on">Məhsul etiketləri gizlədilir</string>
<string name="revanced_hide_merchandise_banners_summary_off">Məhsul etiketləri gÃļstərilir</string>
<!-- 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_fullscreen_ads_feature_not_available_toast">Tam ekran reklamlarÄą gizlətmə yalnÄąz kÃļhnə cihazlarda işləyir</string>
</patch>
@@ -304,7 +322,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_copy_video_url_timestamp_summary_off">DÃŧymə gÃļstərilmir</string>
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
<string name="revanced_remove_viewer_discretion_dialog_title">İzləyici mÃŧlahizə dialoqunu sil</string>
<string name="revanced_remove_viewer_discretion_dialog_title">İzləyici mÃŧlahizə dialoqun sil</string>
<string name="revanced_remove_viewer_discretion_dialog_summary_on">Dialoq silindi</string>
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Dialoq gÃļstərilir</string>
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Bu, yaş məhdudiyyətini ÃļtÃŧrmÃŧr. Sadəcə avtomatik qəbul edir.</string>
@@ -316,7 +334,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_external_downloader_summary_on">YÃŧkləmə dÃŧyməsi oynadÄącÄąda gÃļstərilir</string>
<string name="revanced_external_downloader_summary_off">YÃŧkləmə dÃŧyməsi oynadÄącÄąda gÃļstərilmir</string>
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
<string name="revanced_external_downloader_action_button_title">YÃŧkləmə fəaliyyəti dÃŧyməsini qəbul etmə</string>
<string name="revanced_external_downloader_action_button_title">YÃŧkləmə fəaliyyət dÃŧyməsin qəbul etmə</string>
<string name="revanced_external_downloader_action_button_summary_on">YÃŧkləmə dÃŧyməsi, xarici yÃŧkləyicini aÃ§Äąr</string>
<string name="revanced_external_downloader_action_button_summary_off">YÃŧkləmə dÃŧyməsi tətbiqdəki standart yÃŧkləyicini aÃ§Äąr</string>
<string name="revanced_external_downloader_name_title">YÃŧkləyici paketi adÄą</string>
@@ -567,7 +585,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_disable_rolling_number_animations_summary_off">SÃŧrÃŧşən say animasiyasÄą aÃ§ÄąqdÄąr</string>
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
<string name="revanced_hide_seekbar_title">Video oynadÄącÄąda axtarÄąÅŸ çubuğunu gizlət</string>
<string name="revanced_hide_seekbar_title">Video oynadÄącÄąda axtarÄąÅŸ çubuğun gizlə</string>
<string name="revanced_hide_seekbar_summary_on">Video oynadÄącÄą axtarÄąÅŸ çubuğu gizlidir</string>
<string name="revanced_hide_seekbar_summary_off">Video oynadÄącÄą axtarÄąÅŸ çubuğu gÃļstərilir</string>
<string name="revanced_hide_seekbar_thumbnail_title">Video miniatÃŧrlərdə vaxt çubuğun gizlə</string>
@@ -606,12 +624,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_shorts_tagged_products_title">Etiketlənmiş məhsullarÄą gizlət</string>
<string name="revanced_hide_shorts_tagged_products_summary_on">Etiketlənmiş məhsullar gizlədilir</string>
<string name="revanced_hide_shorts_tagged_products_summary_off">Etiketlənmiş məhsullar gÃļstərilir</string>
<string name="revanced_hide_shorts_location_label_title">Yerləşmə etiketini gizlət</string>
<string name="revanced_hide_shorts_location_label_title">Məkan etiketini gizlət</string>
<string name="revanced_hide_shorts_location_label_summary_on">Məkan etiketi gizlidir</string>
<string name="revanced_hide_shorts_location_label_summary_off">Məkan etiketi gÃļstərilir</string>
<string name="revanced_hide_shorts_save_sound_button_title">Səsi pleylistdə saxlama dÃŧyməsini gizlət</string>
<string name="revanced_hide_shorts_save_sound_button_summary_on">Səsi pleylistdə saxlama gizlidir</string>
<string name="revanced_hide_shorts_save_sound_button_summary_off">Səsi pleylistdə saxlama gÃļstərilir</string>
<string name="revanced_hide_shorts_use_this_sound_button_title">\"Bu səsi istifadə et\" dÃŧyməsini gizlət</string>
<string name="revanced_hide_shorts_use_this_sound_button_summary_on">\"Bu səsi istifadə et\" dÃŧyməsi gizlidir</string>
<string name="revanced_hide_shorts_use_this_sound_button_summary_off">\"Bu səsi istifadə et\" dÃŧyməsi gÃļstərilir</string>
<string name="revanced_hide_shorts_search_suggestions_title">AxtarÄąÅŸ təkliflərini gizlət</string>
<string name="revanced_hide_shorts_search_suggestions_summary_on">AxtarÄąÅŸ təklifləri gizlədilib</string>
<string name="revanced_hide_shorts_search_suggestions_summary_off">AxtarÄąÅŸ təklifləri gÃļstərilir</string>
@@ -665,7 +686,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_timestamp_summary_off">Vaxt mÃļhÃŧrÃŧ gÃļstərilir</string>
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
<string name="revanced_hide_player_popup_panels_title">OynadÄącÄą aÃ§Äąlan pəncərə panellərini gizlət</string>
<string name="revanced_hide_player_popup_panels_title">OynadÄącÄą aÃ§Äąlan pəncərə panellərin gizlə</string>
<string name="revanced_hide_player_popup_panels_summary_on">OynadÄącÄą aÃ§Äąlan pəncərə panelləri gizlidir</string>
<string name="revanced_hide_player_popup_panels_summary_off">OynadÄącÄą aÃ§Äąlan pəncərə panelləri gÃļstərilir</string>
</patch>
@@ -675,7 +696,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_player_overlay_opacity_invalid_toast">OynadÄącÄą ÃļrtÃŧyÃŧnÃŧn qeyri-şəffaflığı 0-100 arasÄą olmalÄądÄąr</string>
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<string name="revanced_ryd_video_likes_hidden_by_video_owner">Gizli</string>
<!-- 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. -->
<string name="revanced_ryd_failure_connection_timeout">\"Bəyənməmə\" mÃŧvəqqəti əlçatmazdÄąr(API vaxtÄą bitdi)</string>
<string name="revanced_ryd_failure_connection_status_code">Bəyənməmə əlçatmazdÄąr (status %d)</string>
@@ -725,7 +745,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_wide_searchbar_summary_off">Geniş axtarÄąÅŸ çubuğu qeyri-aktivdir</string>
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
<string name="revanced_restore_old_seekbar_thumbnails_title">KÃļhnə axtarÄąÅŸ çubuğu miniatÃŧrlərini qaytar</string>
<string name="revanced_restore_old_seekbar_thumbnails_title">KÃļhnə axtarÄąÅŸ çubuğu miniatÃŧrlərin al</string>
<string name="revanced_restore_old_seekbar_thumbnails_summary_on">AxtarÄąÅŸ çubuğu miniatÃŧrləri axtarÄąÅŸ çubuğu ÃŧstÃŧndə gÃļrÃŧnəcək</string>
<string name="revanced_restore_old_seekbar_thumbnails_summary_off">AxtarÄąÅŸ çubuğu miniatÃŧrləri tam ekranda gÃļrÃŧnəcək</string>
</patch>
@@ -771,6 +791,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_general_skipcount_sum_off">ÖtÃŧrmə sayÄąnÄąn izlənməsi aktiv deyil</string>
<string name="revanced_sb_general_min_duration">Minimum bÃļlÃŧm mÃŧddəti</string>
<string name="revanced_sb_general_min_duration_sum">BÃļlÃŧmlər bu dəyərdən (saniyə olaraq) daha qÄąsadÄąrsa gÃļstərilməyəcək və ya ÃļtÃŧrÃŧlməyəcək</string>
<string name="revanced_sb_general_min_duration_invalid">EtibarsÄąz vaxt mÃŧddəti</string>
<string name="revanced_sb_general_uuid">Şəxsi istifadəçi kimliyiniz</string>
<string name="revanced_sb_general_uuid_sum">Bu gizli saxlanÄąlmalÄądÄąr. Bu, parol kimidir və heç kimlə paylaÅŸÄąlmamalÄądÄąr. Kimsə bunu bilsə, onlar sizi təqlid edə bilər</string>
<string name="revanced_sb_general_uuid_invalid">Şəxsi istifadəçi kimliyiniz ən az 30 simvol uzunluğunda olmalÄądÄąr</string>
@@ -788,7 +809,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_settings_export_failed">%s ixrac uğursuz</string>
<string name="revanced_sb_settings_revanced_export_user_id_warning">Tənzimləmələr şəxsi SponsorBlock istifadəçi kimliyi ehtiva edir.\n\nİstifadəçi kimliyiniz parol kimidir və bu paylaÅŸÄąlmamalÄądÄąr.\n</string>
<string name="revanced_sb_settings_revanced_export_user_id_warning_dismiss">Təkrar gÃļstərmə</string>
<string name="revanced_sb_diff_segments">Seqment davranÄąÅŸÄąnÄą dəyişdir</string>
<string name="revanced_sb_diff_segments">BÃļlÃŧm davranÄąÅŸÄąnÄą dəyişdir</string>
<string name="revanced_sb_segments_sponsor">Sponsor</string>
<string name="revanced_sb_segments_sponsor_sum">Ödənişli tanÄątÄąm, Ãļdənişli yÃļnləndirmələr və birbaşa reklamlar. Öz-tanÄątÄąm və ya bəyəndikləri səbəblərə/yaradÄącÄąlara/veb saytlara/məhsullara Ãļdənişsiz çağırÄąÅŸlar etmək ÃŧçÃŧn deyil</string>
<string name="revanced_sb_segments_selfpromo">Ödənişsiz/Öz reklamÄą</string>
@@ -871,8 +892,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_new_segment_time_start">BÃļlÃŧm başladığı vaxt</string>
<string name="revanced_sb_new_segment_time_end">BÃļlÃŧmÃŧn bitmə vaxtÄą</string>
<string name="revanced_sb_new_segment_confirm_title">Vaxtlar dÃŧzgÃŧndÃŧr?</string>
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<string name="revanced_sb_new_segment_confirm_content">BÃļlÃŧm \n\n%1$s\n\n%2$s\n\n(%3$s)\n\nTəqdim etməyə hazÄąrsÄąnÄąz?</string>
<string name="revanced_sb_new_segment_start_is_before_end">Başlanğıc sondan əvvəl olmalÄądÄąr</string>
<string name="revanced_sb_new_segment_mark_locations_first">Əvvəlcə vaxt çubuğunda iki yeri doldur</string>
@@ -891,6 +910,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_stats_username_changed">İstifadəçi adÄą uğurla dəyişdirildi</string>
<string name="revanced_sb_stats_reputation">NÃŧfuzunuz &lt;b&gt;%.2f&lt;/b&gt;</string>
<string name="revanced_sb_stats_submissions">&lt;b&gt;%s&lt;/b&gt; bÃļlÃŧm yaratdÄąnÄąz</string>
<string name="revanced_sb_stats_submissions_sum">BÃļlÃŧmlərinizə baxmaq ÃŧçÃŧn bura toxunun</string>
<string name="revanced_sb_stats_saved_zero">SponsorBlock liderlik lÃļvhəsi</string>
<string name="revanced_sb_stats_saved">İnsanlarÄą &lt;b&gt;%s&lt;/b&gt; bÃļlÃŧmdən xilas etdiniz</string>
<string name="revanced_sb_stats_saved_sum_zero">Qlobal statistikalarÄą və başlÄąca tÃļhfəçiləri gÃļrmək ÃŧçÃŧn bura toxunun</string>
@@ -942,7 +962,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_start_page_entry_9">Trenddə olan</string>
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
<string name="revanced_disable_resuming_shorts_player_title">Shorts oynadıcı davam etdirməsini bağla</string>
<string name="revanced_disable_resuming_shorts_player_title">Shorts oynadÄącÄą başladÄącÄąnÄą bağla</string>
<string name="revanced_disable_resuming_shorts_player_summary_on">Tətbiq aÃ§Äąlanda Shorts oynadÄącÄą davam etməyəcək</string>
<string name="revanced_disable_resuming_shorts_player_summary_off">Tətbiq aÃ§Äąlanda Shorts oynadÄącÄą davam edəcək</string>
</patch>
@@ -1004,7 +1024,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_alt_thumbnail_search_title">AxtarÄąÅŸ nəticələri</string>
<string name="revanced_alt_thumbnail_options_entry_1">Orijinal miniatÃŧrlər</string>
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow &amp; Orijinal miniatÃŧrlər</string>
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Kadr çəkilişləri</string>
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow &amp; Kadr çəkilişlər</string>
<string name="revanced_alt_thumbnail_options_entry_4">Kadr çəkilişləri</string>
<string name="revanced_alt_thumbnail_dearrow_about_summary">DeArrow YouTube videolarÄą ÃŧçÃŧn bÃļlÃŧk mənbəli miniatÃŧrlər təchiz edir. Bu miniatÃŧrlər hər zaman YouTube tərəfindən təmin edilənlərdən daha uyğun olur\n\nƏgər aktivləşdirilərsə, video URL-lər API serverinə gÃļndəriləcək və başqa heç bir məlumat gÃļndərilməyəcək. Videoda DeArrow miniatÃŧrləri yoxdursa, orijinal və ya hələ də kadr çəkilişləri gÃļstərilir\n\nDeArrow haqqÄąnda ətraflÄą Ãļyrənmək ÃŧçÃŧn bura toxun</string>
<string name="revanced_alt_thumbnail_dearrow_connection_toast_title">API əlçatan deyilsə ani bildiriş gÃļstər</string>
@@ -1033,6 +1053,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_announcements_connection_failed">Elan provayderinə bağlanmaq olmadı</string>
<string name="revanced_announcements_dialog_dismiss">Ləğv et</string>
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
<string name="revanced_check_watch_history_domain_name_dialog_title">XĶ™bĶ™rdarlÄąq</string>
<string name="revanced_check_watch_history_domain_name_dialog_message">BaxÄąÅŸ tarixçəniz saxlanmÄąr.&lt;br&gt;&lt;br&gt;Bu çox gÃŧman ki, DNS reklam bloklayÄącÄą və ya şəbəkə proksisinə gÃļrədir.&lt;br&gt;&lt;br&gt;.Bunu dÃŧzəltmək ÃŧçÃŧn s.youtube.com-u&lt;/b&gt; &lt;b&gt;ağ siyahÄąya salÄąn və ya bÃŧtÃŧn DNS bloklayÄącÄąlarÄą və proksiləri bağlayÄąn.</string>
<string name="revanced_check_watch_history_domain_name_dialog_ignore">Təkrar gÃļstərmə</string>
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
<string name="revanced_auto_repeat_title">Avto-təkrarlamanÄą aktivləşdir</string>
<string name="revanced_auto_repeat_summary_on">Avtomatik təkrar aktivləşdirilib</string>
@@ -1059,9 +1084,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_external_browser_summary_off">BağlantÄąlar tətbiqdə aÃ§ÄąlÄąr</string>
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
<string name="revanced_remove_tracking_query_parameter_title">İzləmə sorğusu parametrini sil</string>
<string name="revanced_remove_tracking_query_parameter_summary_on">İzləmə sorğusu parametri bağlantılardan silinir</string>
<string name="revanced_remove_tracking_query_parameter_summary_off">İzləmə sorğusu parametri bağlantılardan silinmir</string>
<string name="revanced_remove_tracking_query_parameter_title">İzləmə sorğusu faktorun sil</string>
<string name="revanced_remove_tracking_query_parameter_summary_on">İzləmə sorğusu faktoru bağlantılardan silinir</string>
<string name="revanced_remove_tracking_query_parameter_summary_off">İzləmə sorğusu faktoru bağlantılardan silinmir</string>
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
<string name="revanced_disable_zoom_haptics_title">YaxÄąnlaşdÄąrma əks-əlaqəsini bağla</string>
@@ -1114,9 +1139,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_spoof_client_summary_on">Qəbuledici saxtalaşdÄąrÄąldÄą</string>
<string name="revanced_spoof_client_summary_off">Qəbuledici dəyişməyib\n\nVideo oynatma işləməyə bilər</string>
<string name="revanced_spoof_client_user_dialog_message">Bu seçimin bağlanmasÄą, video oynatma problemlərinə səbəb ola bilər.</string>
<string name="revanced_spoof_client_use_ios_title">Qəbuledicini iOS olaraq saxtalaşdÄąr</string>
<string name="revanced_spoof_client_use_ios_summary_on">Qəbuledici hazÄąrda iOS-a saxtalaşdÄąrÄąlÄąb\n\nYan təsirlərə daxildir:\nâ€ĸ HDR video yoxdur\nâ€ĸ Daha yÃŧksək video keyfiyyətlər olmaya bilər\nâ€ĸ CanlÄą yayÄąmlar yalnÄąz səs kimi oynadÄąla bilməz</string>
<string name="revanced_spoof_client_use_ios_summary_off">Qəbuledici hazÄąrda Android VR\'ə saxtalaşdÄąrÄąlÄąb \n\nYan təsirlərə daxildir:\nâ€ĸ HDR video yoxdur\nâ€ĸ Uşaq videolarÄą oynadÄąlmÄąr\nâ€ĸ Fasilə verilmiş videolar gÃļzlənilmədən davam edə bilər\nâ€ĸ Aşağı keyfiyyətli Shorts axtarma çubuğu miniatÃŧrləri\nâ€ĸ \"YÃŧklə\" fəaliyyət dÃŧyməsi gizlidir\nâ€ĸ Bitiş ekran kartlarÄą gizlidir</string>
<string name="revanced_spoof_client_type_title">Qəbuledici saxtalaşdÄąrma nÃļvÃŧ</string>
<string name="revanced_spoof_client_ios_force_avc_title">iOS AVC-yə Zorla (H.264)</string>
<string name="revanced_spoof_client_ios_force_avc_summary_on">iOS video kodlayÄącÄą AVC-dir</string>
<string name="revanced_spoof_client_ios_force_avc_summary_off">iOS video kodlayıcı AVC, VP9 və ya AV1-dir</string>
<string name="revanced_spoof_client_ios_force_avc_user_dialog_message">Bunu aktivləşdirmə batareya ÃļmrÃŧnÃŧ yaxÅŸÄąlaşdÄąra və oynatma donmasÄąnÄą dÃŧzəldə bilər.\n\nAVC maksimum 1080p gÃļrÃŧntÃŧ imkanÄąna malikdir və video oynadÄąlmasÄą VP9 və ya AV1-dən daha çox internet məlumatÄąndan istifadə edəcək.</string>
<string name="revanced_spoof_client_about_android_ios_title">iOS saxtakarlığının yan təsirləri</string>
<string name="revanced_spoof_client_about_android_ios_summary">â€ĸ HDR yalnÄąz AV1 kodlayÄącÄą ilə dəstəklənir\nâ€ĸ BaxÄąÅŸ tarixçəsi Ãļdəyici hesab ilə işləmir</string>
<string name="revanced_spoof_client_about_android_vr_title">Android VR saxtakarlığı yan təsirləri</string>
<string name="revanced_spoof_client_about_android_vr_summary">â€ĸ HDR video yoxdurâ€ĸ Uşaq videolarÄą oynadÄąlmÄąr\nâ€ĸ Fasilə verilmiş videolar gÃļzlənilmədən davam edə bilər\nâ€ĸ Aşağı keyfiyyətli Shorts axtarma çubuğu miniatÃŧrləri\nâ€ĸ \"YÃŧklə\" fəaliyyət dÃŧyməsi gizlidir\nâ€ĸ Bitiş ekran kartlarÄą gizlidir</string>
<string name="revanced_spoof_client_storyboard_timeout">Client kiçik şəkillərini təqlid etmə əlçatmazdÄąr (API vaxtÄą bitdi)</string>
<string name="revanced_spoof_client_storyboard_io_exception">Client kiçik şəkillərini təqlid etmə mÃŧvəqqəti əlçatmazdÄąr: %s</string>
</patch>

View File

@@ -32,6 +32,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_confirm_user_dialog_title">Đ’Ņ‹ Ņ…ĐžŅ‡Đ°Ņ†Đĩ ĐŋŅ€Đ°Ņ†ŅĐŗĐŊŅƒŅ†ŅŒ?</string>
<string name="revanced_settings_reset">ĐĄĐēŅ–ĐŊŅƒŅ†ŅŒ</string>
@@ -42,6 +44,13 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_settings_import_reset">НаĐģĐ°Đ´Ņ‹ ReVanced ҁĐēŅ–ĐŊŅƒŅ‚Ņ‹ да ŅŅ‚Đ°ĐŊĐ´Đ°Ņ€Ņ‚ĐŊҋ҅</string>
<string name="revanced_settings_import_success">ІĐŧĐŋĐ°Ņ€Ņ‚Đ°Đ˛Đ°ĐŊа %d ĐŊаĐģад</string>
<string name="revanced_settings_import_failure_parse">ПаĐŧŅ‹ĐģĐēа Ņ–ĐŧĐŋĐ°Ņ€Ņ‚Ņƒ: %s</string>
<string name="revanced_pref_import_export_title">ІĐŧĐŋĐ°Ņ€Ņ‚ / Đ­ĐēҁĐŋĐ°Ņ€Ņ‚</string>
<string name="revanced_pref_import_export_summary">ІĐŧĐŋĐ°Ņ€Ņ‚ / Đ­ĐēҁĐŋĐ°Ņ€Ņ‚ ĐŊаĐģад ReVanced</string>
<!-- Settings about dialog. -->
<string name="revanced_settings_about_links_body">Đ’Ņ‹ Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Đĩ҆Đĩ вĐĩŅ€ŅŅ–ŅŽ ReVanced Patches &lt;i&gt;%s&lt;/i&gt;</string>
<string name="revanced_settings_about_links_dev_header">ĐĐ°Ņ‚Đ°Ņ‚Đēа</string>
<string name="revanced_settings_about_links_dev_body">Đ“ŅŅ‚Đ°Ņ вĐĩŅ€ŅŅ–Ņ С\"ŅŅžĐģŅĐĩŅ†Ņ†Đ° ĐŋаĐŋŅŅ€ŅĐ´ĐŊŅĐš вĐĩŅ€ŅŅ–ŅĐš, Ņ– Đ˛Ņ‹ ĐŧĐžĐļĐ°Ņ†Đĩ ŅŅƒŅ‚Ņ‹ĐēĐŊŅƒŅ†Ņ†Đ° С ĐŊĐĩĐŋŅ€Đ°Đ´ĐąĐ°Ņ‡Đ°ĐŊŅ‹ĐŧŅ– ĐŋŅ€Đ°ĐąĐģĐĩĐŧаĐŧŅ–</string>
<string name="revanced_settings_about_links_header">ĐŅ„Ņ–Ņ†Ņ‹ĐšĐŊŅ‹Ņ ҁĐŋĐ°ŅŅ‹ĐģĐēŅ–</string>
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
@@ -54,14 +63,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
<string name="revanced_settings_about_links_body">Đ’Ņ‹ Đ˛Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°Đĩ҆Đĩ вĐĩŅ€ŅŅ–ŅŽ ReVanced Patches &lt;i&gt;%s&lt;/i&gt;</string>
<string name="revanced_settings_about_links_dev_header">ĐĐ°Ņ‚Đ°Ņ‚Đēа</string>
<string name="revanced_settings_about_links_dev_body">Đ“ŅŅ‚Đ°Ņ вĐĩŅ€ŅŅ–Ņ С\"ŅŅžĐģŅĐĩŅ†Ņ†Đ° ĐŋаĐŋŅŅ€ŅĐ´ĐŊŅĐš вĐĩŅ€ŅŅ–ŅĐš, Ņ– Đ˛Ņ‹ ĐŧĐžĐļĐ°Ņ†Đĩ ŅŅƒŅ‚Ņ‹ĐēĐŊŅƒŅ†Ņ†Đ° С ĐŊĐĩĐŋŅ€Đ°Đ´ĐąĐ°Ņ‡Đ°ĐŊŅ‹ĐŧŅ– ĐŋŅ€Đ°ĐąĐģĐĩĐŧаĐŧŅ–</string>
<string name="revanced_settings_about_links_header">ĐŅ„Ņ–Ņ†Ņ‹ĐšĐŊŅ‹Ņ ҁĐŋĐ°ŅŅ‹ĐģĐēŅ–</string>
<string name="revanced_pref_import_export_title">ІĐŧĐŋĐ°Ņ€Ņ‚ / Đ­ĐēҁĐŋĐ°Ņ€Ņ‚</string>
<string name="revanced_pref_import_export_summary">ІĐŧĐŋĐ°Ņ€Ņ‚ / Đ­ĐēҁĐŋĐ°Ņ€Ņ‚ ĐŊаĐģад ReVanced</string>
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">ĐŸŅ€Đ° ĐŋŅ€Đ°ĐŗŅ€Đ°Đŧ҃</string>
<string name="revanced_settings_screen_01_ads_title">Ай\"ŅĐ˛Ņ‹</string>
@@ -211,6 +212,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_info_cards_section_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģ Ņ–ĐŊŅ„Đ°Ņ€ĐŧĐ°Ņ†Ņ‹ĐšĐŊҋ҅ ĐēĐ°Ņ€Ņ‚</string>
<string name="revanced_hide_info_cards_section_summary_on">РаСдСĐĩĐģ Ņ–ĐŊŅ„Đ°Ņ€ĐŧĐ°Ņ†Ņ‹ĐšĐŊҋ҅ ĐēĐ°Ņ€Ņ‚Đ°Đē ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_hide_info_cards_section_summary_off">ПаĐēаСваĐĩŅ†Ņ†Đ° Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģ Ņ–ĐŊŅ„Đ°Ņ€ĐŧĐ°Ņ†Ņ‹ĐšĐŊҋ҅ ĐēĐ°Ņ€Ņ‚</string>
<string name="revanced_hide_key_concepts_section_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģ ÂĢКĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ ĐŋаĐŊŅŅ†Ņ†Ņ–Âģ</string>
<string name="revanced_hide_key_concepts_section_summary_on">РаСдСĐĩĐģ \"КĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ ĐŋаĐŊŅŅ†Ņ†Ņ–\" ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_hide_key_concepts_section_summary_off">ПаĐēаСаĐŊŅ‹ Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģ ÂĢКĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ ĐŋаĐŊŅŅ†Ņ†Ņ–Âģ</string>
<string name="revanced_hide_transcript_section_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģ ŅŅ‚ŅĐŊĐ°ĐŗŅ€Đ°ĐŧŅ‹</string>
<string name="revanced_hide_transcript_section_summary_on">РаСдСĐĩĐģ ŅŅ‚ŅĐŊĐ°ĐŗŅ€Đ°ĐŧŅ‹ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_hide_transcript_section_summary_off">ПаĐēаСваĐĩŅ†Ņ†Đ° Ņ€Đ°ĐˇĐ´ĐˇĐĩĐģ ŅŅ‚ŅĐŊĐ°ĐŗŅ€Đ°ĐŧŅ‹</string>
@@ -239,14 +243,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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.
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">КĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ ҁĐģĐžĐ˛Ņ‹ Ņ– Ņ„Ņ€Đ°ĐˇŅ‹, ŅĐēŅ–Ņ Ņ‚Ņ€ŅĐąĐ° ŅŅ…Đ°Đ˛Đ°Ņ†ŅŒ, ĐŋадСĐĩĐģĐĩĐŊŅ‹Ņ ĐŊĐžĐ˛Ņ‹ĐŧŅ– Ņ€Đ°Đ´ĐēаĐŧŅ–\n\nĐĄĐģĐžĐ˛Ņ‹ С Đ˛ŅĐģŅ–ĐēŅ–ĐŧŅ– ĐģŅ–Ņ‚Đ°Ņ€Đ°ĐŧŅ– ĐŋĐ°ŅŅŅ€ŅĐ´ĐˇŅ–ĐŊĐĩ Ņ‚Ņ€ŅĐąĐ° ŅžĐ˛ĐžĐ´ĐˇŅ–Ņ†ŅŒ С Đ˛ŅĐģŅ–ĐēŅ–Đŧ Ņ€ŅĐŗŅ–ŅŅ‚Ņ€Đ°Đŧ (ĐŊаĐŋҀҋĐēĐģад: iPhone, TikTok, LeBlanc)</string>
<string name="revanced_hide_keyword_content_about_title">Ай ҄ҖĐģŅŒŅ‚Ņ€Đ°Ņ†Ņ‹Ņ– ĐēĐģŅŽŅ‡Đ°Đ˛Ņ‹Ņ… ҁĐģĐžŅž</string>
<string name="revanced_hide_keyword_content_about_summary">ГаĐģĐžŅžĐŊĐ°Ņ/ПадĐŋҖҁĐēа/Đ’Ņ‹ĐŊŅ–ĐēŅ– ĐŋĐžŅˆŅƒĐē҃ ҄ҖĐģŅŒŅ‚Ņ€ŅƒŅŽŅ†Ņ†Đ°, Đēай ŅŅ…Đ°Đ˛Đ°Ņ†ŅŒ СĐŧĐĩŅŅ†Ņ–Đ˛Đ°, ŅĐēĐžĐĩ ҁ҃ĐŋадаĐĩ С ĐēĐģŅŽŅ‡Đ°Đ˛Ņ‹ĐŧŅ– Ņ„Ņ€Đ°ĐˇĐ°ĐŧŅ–\n\nАйĐŧĐĩĐļаваĐŊĐŊŅ–\nâ€ĸ НĐĩĐēĐ°Ņ‚ĐžŅ€Ņ‹Ņ ŅˆĐžŅ€Ņ‚Ņ‹ ĐŧĐžĐŗŅƒŅ†ŅŒ ĐąŅ‹Ņ†ŅŒ ĐŊĐĩ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹\nâ€ĸ НĐĩĐēĐ°Ņ‚ĐžŅ€Ņ‹Ņ ĐēаĐŧĐŋаĐŊĐĩĐŊ҂ҋ ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐģҌĐŊҖ҆ĐēĐ°ĐŗĐ° Ņ–ĐŊŅ‚ŅŅ€Ņ„ĐĩĐšŅŅƒ ĐŧĐžĐŗŅƒŅ†ŅŒ ĐąŅ‹Ņ†ŅŒ ĐŊĐĩ ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹\nâ€ĸ ĐŸĐžŅˆŅƒĐē Đŋа ĐēĐģŅŽŅ‡Đ°Đ˛Ņ‹Đŧ ҁĐģОвĐĩ ĐŧĐžĐļа ĐŊĐĩ Đ´Đ°Ņ†ŅŒ Đ˛Ņ‹ĐŊŅ–ĐēĐ°Ņž</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 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>
<!-- 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_length">ĐŅĐŋŅ€Đ°Đ˛Ņ–ĐģҌĐŊаĐĩ ĐēĐģŅŽŅ‡Đ°Đ˛ĐžĐĩ ҁĐģОва. \"%1$s\" СĐŧŅŅˆŅ‡Đ°Đĩ ĐŧĐĩĐŊ҈ Са %2$d ҁҖĐŧваĐģĐ°Ņž</string>
<string name="revanced_hide_keyword_toast_invalid_broad">КĐģŅŽŅ‡Đ°Đ˛ĐžĐĩ ҁĐģОва \"%s\" ŅŅ…Đ°Đ˛Đ°Đĩ ŅžŅĐĩ Đ˛Ņ–Đ´ŅĐ°</string>
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<string name="revanced_hide_general_ads_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ Đ°ĐŗŅƒĐģҌĐŊŅƒŅŽ Ņ€ŅĐēĐģаĐŧ҃</string>
@@ -427,7 +426,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_home_button_summary_on">КĐŊĐžĐŋĐēа \"ДадоĐŧ҃\" ŅŅ…Đ°Đ˛Đ°ĐŊа</string>
<string name="revanced_hide_home_button_summary_off">ПаĐēаСаĐŊа ĐēĐŊĐžĐŋĐēа \"ДадоĐŧ҃\".</string>
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<string name="revanced_hide_shorts_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ŅˆĐžŅ€Ņ‚Ņ‹</string>
<string name="revanced_hide_shorts_button_title">ĐĄŅ…Đ°Đ˛Đ°Ņ†ŅŒ ĐēĐŊĐžĐŋĐē҃ \"Shorts\"</string>
<string name="revanced_hide_shorts_button_summary_on">КĐŊĐžĐŋĐēа Shorts ŅŅ…Đ°Đ˛Đ°ĐŊа</string>
<string name="revanced_hide_shorts_button_summary_off">ПаĐēаСаĐŊа ĐēĐŊĐžĐŋĐēа Shorts</string>
<!-- The Create button has no display name. Translate normally. -->
@@ -675,7 +674,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_player_overlay_opacity_invalid_toast">НĐĩĐŋŅ€Đ°ĐˇŅ€Ņ‹ŅŅ‚Đ°ŅŅ†ŅŒ ĐŊаĐēĐģадаĐŊĐŊŅ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐģҌĐŊŅ–Đēа ĐŋĐ°Đ˛Ņ–ĐŊĐŊа ĐąŅ‹Ņ†ŅŒ ĐŋаĐŧŅ–Đļ 0-100</string>
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<string name="revanced_ryd_video_likes_hidden_by_video_owner">ĐĄŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<!-- 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. -->
<string name="revanced_ryd_failure_connection_timeout">АдСĐŊаĐēŅ– \"НĐĩ ĐŋадайаĐĩŅ†Ņ†Đ°\" Ņ‡Đ°ŅĐžĐ˛Đ° ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹Ņ (Ņ‡Đ°Ņ Ņ‡Đ°ĐēаĐŊĐŊŅ API ҁĐēĐžĐŊŅ‡Ņ‹ŅžŅŅ)</string>
<string name="revanced_ryd_failure_connection_status_code">Đ”Ņ‹ĐˇĐģаКĐēŅ– ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹Ņ (ŅŅ‚Đ°Ņ‚ŅƒŅ %d)</string>
@@ -864,14 +862,13 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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>
<string name="revanced_sb_new_segment_mark_time_as_question">ĐŖŅŅ‚Đ°ĐģŅĐ˛Đ°Ņ†ŅŒ %s ҃ ŅĐēĐ°ŅŅ†Ņ– ĐŋĐ°Ņ‡Đ°Ņ‚Đē҃ айО ĐēаĐŊŅ†Đ° ĐŊĐžĐ˛Đ°ĐŗĐ° ҁĐĩĐŗĐŧĐĩĐŊŅ‚Đ°?</string>
<string name="revanced_sb_new_segment_mark_start">ĐŋĐ°Ņ‡Đ°Ņ†ŅŒ</string>
<string name="revanced_sb_new_segment_mark_end">ĐēаĐŊĐĩ҆</string>
<string name="revanced_sb_new_segment_now">ĐˇĐ°Ņ€Đ°Đˇ</string>
<string name="revanced_sb_new_segment_time_start">Đ§Đ°Ņ ĐŋĐ°Ņ‡Đ°Ņ‚Đē҃ ҁĐĩĐŗĐŧĐĩĐŊŅ‚Đ°</string>
<string name="revanced_sb_new_segment_time_end">Đ§Đ°Ņ СаĐēаĐŊŅ‡ŅĐŊĐŊŅ ҁĐĩĐŗĐŧĐĩĐŊŅ‚Đ°</string>
<string name="revanced_sb_new_segment_confirm_title">ĐĻŅ– ĐŋŅ€Đ°Đ˛Ņ–ĐģҌĐŊŅ‹ Ņ‡Đ°Ņ?</string>
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<string name="revanced_sb_new_segment_confirm_content">ĐĄĐĩĐŗĐŧĐĩĐŊŅ‚ ад\n\n%1$s\nда\n%2$s\n\n(%3$s)\n\nĐ“Đ°Ņ‚ĐžĐ˛Ņ‹ адĐŋŅ€Đ°Đ˛Ņ–Ņ†ŅŒ?</string>
<string name="revanced_sb_new_segment_start_is_before_end">ĐŸĐ°Ņ‡Ņ‹ĐŊĐ°Ņ†ŅŒ Ņ‚Ņ€ŅĐąĐ° Ņ€Đ°ĐŊĐĩĐš Са ĐēаĐŊĐĩ҆</string>
<string name="revanced_sb_new_segment_mark_locations_first">ĐĄĐŋĐ°Ņ‡Đ°Ņ‚Đē҃ адСĐŊĐ°Ņ‡Ņ†Đĩ два ĐŧĐĩҁ҆ҋ ĐŊа ĐŋаĐŊŅĐģŅ– Ņ‡Đ°ŅŅƒ</string>
@@ -988,6 +985,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_seekbar_custom_color_invalid">ĐŅĐŋŅ€Đ°Đ˛Ņ–ĐģҌĐŊаĐĩ СĐŊĐ°Ņ‡ŅĐŊĐŊĐĩ ĐēĐžĐģĐĩŅ€Ņƒ ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃. Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚ĐžŅžĐ˛Đ°ĐĩŅ†Ņ†Đ° СĐŊĐ°Ņ‡ŅĐŊĐŊĐĩ Đŋа СĐŧĐ°ŅžŅ‡Đ°ĐŊĐŊŅ–.</string>
</patch>
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
<string name="revanced_bypass_image_region_restrictions_title">ĐĐąŅ‹Ņ…ĐžĐ´ айĐŧĐĩĐļаваĐŊĐŊŅŅž Ņ€ŅĐŗŅ–Ņ‘ĐŊ҃</string>
<string name="revanced_bypass_image_region_restrictions_summary_on">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐŊĐŊĐĩ Ņ…Đ°ŅŅ‚Đ° Đ˛Ņ–Đ´Đ°Ņ€Ņ‹ŅĐ°Ņž yt4.ggpht.com</string>
<string name="revanced_bypass_image_region_restrictions_summary_off">Đ’Ņ‹ĐēĐ°Ņ€Ņ‹ŅŅ‚Đ°ĐŊĐŊĐĩ Đ°Ņ€Ņ‹ĐŗŅ–ĐŊаĐģҌĐŊĐ°ĐŗĐ° Ņ…Đ°ŅŅ‚Đ° Đ˛Ņ–Đ´Đ°Ņ€Ņ‹ŅĐ°Ņž\n\nĐŖĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°Đš ĐžĐŋ҆ҋҖ ĐŧĐžĐļа Đ˛Ņ‹ĐŋŅ€Đ°Đ˛Ņ–Ņ†ŅŒ Đ°Đ´ŅŅƒŅ‚ĐŊŅ–Ņ‡Đ°ŅŽŅ‡Ņ‹Ņ Đ˛Ņ–Đ´Đ°Ņ€Ņ‹ŅŅ‹, ŅĐēŅ–Ņ СайĐģаĐēŅ–Ņ€Đ°Đ˛Đ°ĐŊŅ‹Ņ Ņž ĐŊĐĩĐēĐ°Ņ‚ĐžŅ€Ņ‹Ņ… Ņ€ŅĐŗŅ–Ņ‘ĐŊĐ°Ņ…</string>
</patch>
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
@@ -1029,6 +1029,10 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_announcements_connection_failed">НĐĩ ŅžĐ´Đ°ĐģĐžŅŅ ĐŋадĐēĐģŅŽŅ‡Ņ‹Ņ†Ņ†Đ° да ĐŋĐ°ŅŅ‚Đ°ŅžŅˆŅ‡Ņ‹Đēа ай\"ŅŅž</string>
<string name="revanced_announcements_dialog_dismiss">Ņ€Đ°ŅŅĐģĐ°ĐąŅ–Ņ†Ņ†Đ°</string>
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
<string name="revanced_check_watch_history_domain_name_dialog_title">ĐŖĐ˛Đ°ĐŗĐ°</string>
<string name="revanced_check_watch_history_domain_name_dialog_ignore">БоĐģҌ҈ ĐŊĐĩ ĐŋаĐēĐ°ĐˇĐ˛Đ°Ņ†ŅŒ</string>
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
<string name="revanced_auto_repeat_title">ĐŖĐēĐģŅŽŅ‡Ņ‹Ņ†ŅŒ Đ°ŅžŅ‚Đ°ĐŧĐ°Ņ‚Ņ‹Ņ‡ĐŊŅ‹ ĐŋĐ°ŅžŅ‚ĐžŅ€</string>
<string name="revanced_auto_repeat_summary_on">ĐŅžŅ‚Đ°ĐŧĐ°Ņ‚Ņ‹Ņ‡ĐŊŅ‹ ĐŋĐ°ŅžŅ‚ĐžŅ€ ҃ĐēĐģŅŽŅ‡Đ°ĐŊŅ‹</string>
@@ -1110,7 +1114,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_spoof_client_summary_on">КĐģŅ–ĐĩĐŊŅ‚ ĐŋĐ°Đ´Ņ€ĐžĐąĐģĐĩĐŊŅ‹</string>
<string name="revanced_spoof_client_summary_off">КĐģŅ–ĐĩĐŊŅ‚ ĐŊĐĩ ĐŋĐ°Đ´Ņ€ĐžĐąĐģĐĩĐŊŅ‹\n\nĐŸŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐļа ĐŊĐĩ ĐŋŅ€Đ°Ņ†Đ°Đ˛Đ°Ņ†ŅŒ</string>
<string name="revanced_spoof_client_user_dialog_message">АдĐēĐģŅŽŅ‡ŅĐŊĐŊĐĩ ĐŗŅŅ‚Đ°Đš ĐŊаĐģĐ°Đ´Ņ‹ ĐŧĐžĐļа Đ˛Ņ‹ĐēĐģŅ–ĐēĐ°Ņ†ŅŒ ĐŋŅ€Đ°ĐąĐģĐĩĐŧŅ‹ С ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ĐŊĐŊĐĩĐŧ Đ˛Ņ–Đ´ŅĐ°.</string>
<string name="revanced_spoof_client_use_ios_title">ĐŸĐ°Đ´Ņ€ĐžĐąĐēа ĐēĐģŅ–ĐĩĐŊŅ‚Đ° Đ´ĐģŅ iOS</string>
<string name="revanced_spoof_client_about_android_vr_summary">â€ĸ ĐŅĐŧа HDR-Đ˛Ņ–Đ´ŅĐ°\nâ€ĸ Đ”ĐˇŅ–Ņ†ŅŅ‡Ņ‹Ņ Đ˛Ņ–Đ´ŅĐ° ĐŊĐĩ ĐŋŅ€Đ°ĐšĐŗŅ€Đ°Đ˛Đ°ŅŽŅ†Ņ†Đ°\nâ€ĸ ĐŸŅ€Ņ‹ĐŋŅ‹ĐŊĐĩĐŊŅ‹Ņ Đ˛Ņ–Đ´ŅĐ° ĐŧĐžĐŗŅƒŅ†ŅŒ адĐŊĐ°ŅžĐģŅŅ†Ņ†Đ° Đ˛Ņ‹ĐŋадĐēĐžĐ˛Ņ‹Đŧ ҇ҋĐŊаĐŧ\nâ€ĸ ĐŅ–ĐˇĐēĐ°Ņ ŅĐēĐ°ŅŅ†ŅŒ ĐŧŅ–ĐŊŅ–ŅŅ†ŅŽŅ€ ĐŊа ĐŋаĐŊŅĐģŅ– ĐŋĐžŅˆŅƒĐē҃ Shorts\nâ€ĸ КĐŊĐžĐŋĐēа дСĐĩŅĐŊĐŊŅ ĐĄĐŋаĐŧĐŋĐ°Đ˛Đ°Ņ†ŅŒ ŅŅ…Đ°Đ˛Đ°ĐŊа\nâ€ĸ ĐšĐ°Ņ€Ņ‚ĐēŅ– ĐēаĐŊŅ†Đ°Đ˛ĐžĐŗĐ° ŅĐēŅ€Đ°ĐŊа ŅŅ…Đ°Đ˛Đ°ĐŊŅ‹</string>
<string name="revanced_spoof_client_storyboard_timeout">ĐœŅ–ĐŊŅ–ŅŅ†ŅŽŅ€Ņ‹ ĐēĐģŅ–ĐĩĐŊŅ‚Đ° Spoof ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹Ņ (Ņ‡Đ°Ņ Ņ‡Đ°ĐēаĐŊĐŊŅ API ҁĐēĐžĐŊŅ‡Ņ‹ŅžŅŅ)</string>
<string name="revanced_spoof_client_storyboard_io_exception">ĐœŅ–ĐŊŅ–ŅŅ†ŅŽŅ€Ņ‹ ĐēĐģŅ–ĐĩĐŊŅ‚Đ° Spoof Ņ‡Đ°ŅĐžĐ˛Đ° ĐŊĐĩĐ´Đ°ŅŅ‚ŅƒĐŋĐŊŅ‹Ņ: %s</string>
</patch>

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_confirm_user_dialog_title">āφāĻĒāύāĻŋ āĻ•āĻŋ āĻāĻ—āĻŋā§Ÿā§‡ āϝ⧇āϤ⧇ āχāĻšā§āϛ⧁āĻ•?</string>
<string name="revanced_settings_reset">āφāĻŦāĻžāϰ āϏ⧇āϟ āĻ•āϰ⧁āύ</string>
@@ -42,6 +44,13 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_settings_import_reset">ReVanced āϏ⧇āϟāĻŋāĻ‚ āĻĄāĻŋāĻĢāĻ˛ā§āϟ āϏ⧇āϟ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_settings_import_success">%d āϏ⧇āϟāĻŋāĻ‚ āφāĻŽāĻĻāĻžāύāĻŋ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_settings_import_failure_parse">āφāĻŽāĻĻāĻžāύāĻŋ āĻ•āϰāĻž āϝāĻžā§ŸāύāĻŋ: %s</string>
<string name="revanced_pref_import_export_title">āφāĻŽāĻĻāĻžāύāĻŋ āĻāĻŦāĻ‚ āϰāĻĒā§āϤāĻžāύāĻŋ</string>
<string name="revanced_pref_import_export_summary">ReVanced āϏ⧇āϟāĻŋāĻ‚ āφāĻŽāĻĻāĻžāύāĻŋ āĻŦāĻž āϰāĻĒā§āϤāĻžāύāĻŋ āĻ•āϰ⧁āύ</string>
<!-- Settings about dialog. -->
<string name="revanced_settings_about_links_body">āφāĻĒāύāĻŋ ReVanced āĻĒā§āϝāĻžāϚ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖ &lt;i&gt;%s&lt;/i&gt; āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϛ⧇āύ</string>
<string name="revanced_settings_about_links_dev_header">āĻĻā§āϰāĻˇā§āϟāĻŦā§āϝ</string>
<string name="revanced_settings_about_links_dev_body">āĻāχ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖ āĻāĻ•āϟāĻŋ āĻĒā§āϰāĻžāĻ•-āĻĒā§āϰāĻ•āĻžāĻļāύāĻž āĻāĻŦāĻ‚ āĻāϤ⧇ āφāĻĒāύāĻŋ āĻ…āύāĻžāĻ•āĻžāĻ™ā§āĻ–āĻŋāϤ āϏāĻŽāĻ¸ā§āϝāĻžāϰ āϏāĻŽā§āĻŽā§āĻ–āĻŋāύ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āύ</string>
<string name="revanced_settings_about_links_header">āĻ…āĻĢāĻŋāĻļā§āϝāĻžāϞ āϞāĻŋāĻ‚āĻ•āϏāĻŽā§‚āĻš</string>
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
@@ -54,14 +63,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
<string name="revanced_settings_about_links_body">āφāĻĒāύāĻŋ ReVanced āĻĒā§āϝāĻžāϚ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖ &lt;i&gt;%s&lt;/i&gt; āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻ•āϰāϛ⧇āύ</string>
<string name="revanced_settings_about_links_dev_header">āĻĻā§āϰāĻˇā§āϟāĻŦā§āϝ</string>
<string name="revanced_settings_about_links_dev_body">āĻāχ āϏāĻ‚āĻ¸ā§āĻ•āϰāĻŖ āĻāĻ•āϟāĻŋ āĻĒā§āϰāĻžāĻ•-āĻĒā§āϰāĻ•āĻžāĻļāύāĻž āĻāĻŦāĻ‚ āĻāϤ⧇ āφāĻĒāύāĻŋ āĻ…āύāĻžāĻ•āĻžāĻ™ā§āĻ–āĻŋāϤ āϏāĻŽāĻ¸ā§āϝāĻžāϰ āϏāĻŽā§āĻŽā§āĻ–āĻŋāύ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āύ</string>
<string name="revanced_settings_about_links_header">āĻ…āĻĢāĻŋāĻļā§āϝāĻžāϞ āϞāĻŋāĻ‚āĻ•āϏāĻŽā§‚āĻš</string>
<string name="revanced_pref_import_export_title">āφāĻŽāĻĻāĻžāύāĻŋ āĻāĻŦāĻ‚ āϰāĻĒā§āϤāĻžāύāĻŋ</string>
<string name="revanced_pref_import_export_summary">ReVanced āϏ⧇āϟāĻŋāĻ‚ āφāĻŽāĻĻāĻžāύāĻŋ āĻŦāĻž āϰāĻĒā§āϤāĻžāύāĻŋ āĻ•āϰ⧁āύ</string>
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">āϏāĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāϤ</string>
<string name="revanced_settings_screen_01_ads_title">āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāύ</string>
@@ -201,6 +202,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_hide_chips_shelf_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>
<string name="revanced_hide_info_cards_section_title">āϤāĻĨā§āϝ āĻ•āĻžāĻ°ā§āĻĄ āϏ⧇āĻ•āĻļāύ āϞ⧁āĻ•āĻžāύ</string>
<string name="revanced_hide_info_cards_section_summary_on">āϤāĻĨā§āϝ āĻ•āĻžāĻ°ā§āĻĄ āϏ⧇āĻ•āĻļāύ āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<string name="revanced_hide_info_cards_section_summary_off">āϤāĻĨā§āϝ āĻ•āĻžāĻ°ā§āĻĄ āϏ⧇āĻ•āĻļāύ āĻĒā§āϰāĻĻāĻ°ā§āĻļāĻŋāϤ āĻšā§Ÿā§‡āϛ⧇</string>
@@ -231,13 +233,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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.
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">āϞ⧁āĻ•āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻāĻŦāĻ‚ āĻŦāĻžāĻ•ā§āϝāĻžāĻ‚āĻļ, āύāϤ⧁āύ āϞāĻžāχāύ⧇ āĻĒ⧃āĻĨāĻ• āĻ•āϰāĻž\n\nāĻļāĻŦā§āĻĻ⧇āϰ āĻŽāĻžāĻā§‡ āĻŦ⧜ āĻšāĻžāϤ⧇āϰ āĻ…āĻ•ā§āώāϰ āĻĨāĻžāĻ•āϞ⧇ āϤāĻž āĻ…āĻŦāĻļā§āϝāχ āϏāĻ āĻŋāĻ• āφāĻŦāϰāϪ⧇ āϞāĻŋāĻ–āϤ⧇ āĻšāĻŦ⧇ (āωāĻĻāĻžāĻšāϰāĻŖ: iPhone, TikTok, LeBlanc)</string>
<string name="revanced_hide_keyword_content_about_title">āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻĢāĻŋāĻ˛ā§āϟāĻžāϰāĻŋāĻ‚ āϏāĻŽā§āĻĒāĻ°ā§āϕ⧇</string>
<string name="revanced_hide_keyword_content_about_summary">āĻĒā§āϰāϧāĻžāύ āĻĒāĻžāϤāĻž/āϏāĻžāĻŦāĻ¸ā§āĻ•ā§āϰāĻŋāĻĒāĻļāύ/āĻ…āύ⧁āϏāĻ¨ā§āϧāĻžāύ āĻĢāϞāĻžāĻĢāϞ āϗ⧁āϞ⧋ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āĻŦāĻžāĻ•ā§āϝāĻžāĻ‚āĻļ⧇āϰ āϏāĻžāĻĨ⧇ āĻŽāĻŋāϞāĻŋā§Ÿā§‡ āϞ⧁āĻ•āĻžāύ⧋āϰ āϜāĻ¨ā§āϝ āĻĢāĻŋāĻ˛ā§āϟāĻžāϰ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇\n\nāϏ⧀āĻŽāĻžāĻŦāĻĻā§āϧāϤāĻž\nâ€ĸ āĻ•āĻŋāϛ⧁ Shorts āύāĻžāĻ“ āϞ⧁āĻ•āĻžāύ⧋ āĻšāϤ⧇ āĻĒāĻžāϰ⧇\nâ€ĸ āĻ•āĻŋāϛ⧁ āχāωāφāχ āωāĻĒāĻžāĻĻāĻžāύ āύāĻžāĻ“ āϞ⧁āĻ•āĻžāύ⧋ āĻšāϤ⧇ āĻĒāĻžāϰ⧇\nâ€ĸ āϕ⧋āύ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄ āϏāĻžāĻ°ā§āϚ āĻ•āϰāϞ⧇ āϕ⧋āύ āĻĢāϞāĻžāĻĢāϞ āύāĻžāĻ“ āĻĻ⧇āĻ–āĻžāϤ⧇ āĻĒāĻžāϰ⧇</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 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>
<!-- 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_length">āĻ¤ā§āϰ⧁āϟāĻŋāĻĒā§‚āĻ°ā§āĻŖ āϕ⧀āĻ“ā§ŸāĻžāĻ°ā§āĻĄāĨ¤ \'%1$s\' āϟāĻŋ %2$d āĻ…āĻ•ā§āώāϰ āĻĨ⧇āϕ⧇ āĻ•āĻŽ</string>
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<string name="revanced_hide_general_ads_title">āϏāĻžāϧāĻžāϰāĻŖ āĻŦāĻŋāĻœā§āĻžāĻžāĻĒāύ āϞ⧁āĻ•āĻžāύ</string>
@@ -603,7 +601,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_player_overlay_opacity_invalid_toast">āĻĒā§āĻ˛ā§‡ā§ŸāĻžāϰ āĻ“āĻ­āĻžāϰāϞ⧇ āĻ…āĻ¸ā§āĻŦāĻšā§āĻ›āϤāĻž āĻ…āĻŦāĻļā§āϝāχ ā§Ļ-ā§§ā§Ļā§Ļ āĻāϰ āĻŽāĻ§ā§āϝ⧇ āĻšāϤ⧇ āĻšāĻŦ⧇</string>
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<string name="revanced_ryd_video_likes_hidden_by_video_owner">āϞ⧁āĻ•āĻŋā§Ÿā§‡ āĻ°ā§Ÿā§‡āϛ⧇</string>
<!-- 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. -->
<string name="revanced_ryd_failure_connection_timeout">āĻ…āĻĒāĻ›āĻ¨ā§āĻĻ āϏāĻžāĻŽā§ŸāĻŋāĻ•āĻ­āĻžāĻŦ⧇ āωāĻĒāϞāĻ­ā§āϝ āύ⧟ (API āϏāĻŽā§Ÿ āĻļ⧇āώ āĻšā§Ÿā§‡āϛ⧇)</string>
<string name="revanced_ryd_failure_connection_status_code">āĻ…āĻĒāĻ›āĻ¨ā§āĻĻ āωāĻĒāϞāĻ­ā§āϝ āύ⧟ (āĻ…āĻŦāĻ¸ā§āĻĨāĻž %d)</string>
@@ -798,8 +795,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_sb_new_segment_time_start">āϏ⧇āĻ—āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āĻļ⧁āϰ⧁ āĻšāĻ“āϝāĻŧāĻžāϰ āϏāĻŽāϝāĻŧ</string>
<string name="revanced_sb_new_segment_time_end">āϏ⧇āĻ—āĻŽā§‡āĻ¨ā§āϟāϟāĻŋ āĻļ⧇āώ āĻšāĻ“āϝāĻŧāĻžāϰ āϏāĻŽāϝāĻŧ</string>
<string name="revanced_sb_new_segment_confirm_title">āϏāĻŽāϝāĻŧāĻ•āĻžāϞ āĻ•āĻŋ āϏāĻ āĻŋāĻ•?</string>
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<string name="revanced_sb_new_segment_confirm_content">āϏ⧇āĻ—āĻŽā§‡āĻ¨ā§āϟ āϏāĻŽā§ŸāĻ•āĻžāϞ\n\n%1$s\nāĻĨ⧇āϕ⧇\n%2$s\n\n(%3$s)\n\nāϜāĻŽāĻž āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāĻ¸ā§āϤ⧁āϤ?</string>
<string name="revanced_sb_new_segment_start_is_before_end">āĻļ⧁āϰ⧁ āĻ…āĻŦāĻļā§āϝāχ āĻļ⧇āώ⧇āϰ āφāϗ⧇ āĻšāϤ⧇ āĻšāĻŦ⧇</string>
<string name="revanced_sb_new_segment_mark_locations_first">āφāϗ⧇ āϏāĻŽā§Ÿ āĻŦāĻžāϰ⧇ āĻĻ⧁āϟāĻŋ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāύ āϚāĻŋāĻšā§āύāĻŋāϤ āĻ•āϰ⧁āύ</string>
@@ -958,6 +953,10 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_announcements_connection_failed">āĻ˜ā§‹āώāύāĻžāĻĻāĻžāϤāĻžāϰ āϏāĻžāĻĨ⧇ āϏāĻŽā§āĻĒāĻ°ā§āĻ• āĻ¸ā§āĻĨāĻžāĻĒāύ āĻŦā§āϝāĻ°ā§āĻĨ āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_announcements_dialog_dismiss">āĻŦāĻžāϤāĻŋāϞ āĻ•āϰ⧁āύ</string>
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
<string name="revanced_check_watch_history_domain_name_dialog_title">āϏāϤāĻ°ā§āϕ⧀āĻ•āϰāĻŖ</string>
<string name="revanced_check_watch_history_domain_name_dialog_ignore">āφāĻŦāĻžāϰ āĻĻ⧇āĻ–āĻžāĻŦ⧇āύ āύāĻž</string>
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
<string name="revanced_auto_repeat_title">āĻ¸ā§āĻŦ⧟āĻ‚āĻ•ā§āϰāĻŋ⧟āĻ­āĻžāĻŦ⧇-āφāĻŦāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āϏāĻ•ā§āϰāĻŋ⧟ āĻ•āϰ⧁āύ</string>
<string name="revanced_auto_repeat_summary_on">āĻ¸ā§āĻŦ⧟āĻ‚āĻ•ā§āϰāĻŋ⧟āĻ­āĻžāĻŦ⧇-āφāĻŦāĻžāϰ āĻĻ⧇āĻ–āĻžāύ⧋ āϏāĻ•ā§āϰāĻŋ⧟ āĻšā§Ÿā§‡āϛ⧇</string>
@@ -1039,7 +1038,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<string name="revanced_spoof_client_summary_on">āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰāĻž āĻšā§Ÿā§‡āϛ⧇</string>
<string name="revanced_spoof_client_summary_off">āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰāĻž āĻšā§ŸāύāĻŋ\n\nāĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻ āĻŋāĻ•āĻŽāϤ⧋ āĻ•āĻžāϜ āύāĻžāĻ“ āĻ•āϰāϤ⧇ āĻĒāĻžāϰ⧇</string>
<string name="revanced_spoof_client_user_dialog_message">āĻāχ āϏ⧇āϟāĻŋāĻ‚āϟāĻŋ āĻŦāĻ¨ā§āϧ āĻ•āϰāĻžāϰ āĻĢāϞ⧇ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻ¤ā§āϰ⧁āϟāĻŋ āĻšāϤ⧇ āĻĒāĻžāϰ⧇āĨ¤</string>
<string name="revanced_spoof_client_use_ios_title">āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ iOS āĻ āĻ¸ā§āĻĒ⧁āĻĢ āĻ•āϰ⧁āύ</string>
<string name="revanced_spoof_client_about_android_vr_summary">â€ĸ āϕ⧋āύāĻ“ HDR āĻ­āĻŋāĻĄāĻŋāĻ“ āύ⧇āχ\nâ€ĸ āĻŦāĻžāĻšā§āϚāĻžāĻĻ⧇āϰ āĻ­āĻŋāĻĄāĻŋāĻ“ āĻĒā§āϞ⧇āĻŦā§āϝāĻžāĻ• āĻšāϝāĻŧ āύāĻž\nâ€ĸ āĻŦāĻŋāϰāϤāĻŋ āĻĻ⧇āĻ“āϝāĻŧāĻž āĻ­āĻŋāĻĄāĻŋāĻ“āϗ⧁āϞāĻŋ āĻāϞ⧋āĻŽā§‡āϞ⧋āĻ­āĻžāĻŦ⧇ āφāĻŦāĻžāϰ āĻļ⧁āϰ⧁ āĻšāϤ⧇ āĻĒāĻžāϰ⧇\nâ€ĸ āύāĻŋāĻŽā§āύāĻŽāĻžāύ⧇āϰ āĻļāĻ°ā§āϟāϏ āϏāĻŋāĻ•āĻŦāĻžāϰ āĻĨāĻžāĻŽā§āĻŦāύ⧇āϞ\nâ€ĸ āĻĄāĻžāωāύāϞ⧋āĻĄ āĻ…ā§āϝāĻžāĻ•āĻļāύ āĻŦā§‹āϤāĻžāĻŽ āϏāĻŦāϏāĻŽāϝāĻŧ āϞ⧁āĻ•āĻžāύ⧋ āĻĨāĻžāϕ⧇\nâ€ĸ āĻļ⧇āώ āĻ¸ā§āĻ•ā§āϰāĻŋāύ āĻ•āĻžāĻ°ā§āĻĄ āϏāĻŦāϏāĻŽāϝāĻŧ āϞ⧁āĻ•āĻžāύ⧋ āĻĨāĻžāϕ⧇</string>
<string name="revanced_spoof_client_storyboard_timeout">āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ āĻ¸ā§āĻĒ⧁āĻĢ āĻĨāĻžāĻŽā§āĻŦāύ⧇āχāϞ āϏāĻžāĻŽā§ŸāĻŋāĻ•āĻ­āĻžāĻŦ⧇ āωāĻĒāϞāĻ­ā§āϝ āύ⧟ (API āϏāĻŽā§Ÿ āĻļ⧇āώ āĻšā§Ÿā§‡āϛ⧇)</string>
<string name="revanced_spoof_client_storyboard_io_exception">āĻ¸ā§āĻĒ⧁āĻĢ āĻ•ā§āϞāĻžā§Ÿā§‡āĻ¨ā§āϟ āĻĨāĻžāĻŽā§āĻŦāύ⧇āχāϞ āϏāĻžāĻŽā§ŸāĻŋāĻ•āĻ­āĻžāĻŦ⧇ āωāĻĒāϞāĻ­ā§āϝ āύ⧟: %s</string>
</patch>

View File

@@ -32,15 +32,16 @@ This is because Crowdin requires temporarily flattening this file and removing t
-->
<resources>
<app id="shared">
<patch id="misc.checks.BaseCheckEnvironmentPatch">
</patch>
<patch id="misc.settings.BaseSettingsResourcePatch">
<!-- Settings about dialog. -->
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
@@ -57,7 +58,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
<!-- '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.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- 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">
@@ -171,8 +172,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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. -->
<!-- Do not rearrange the (hour):(minute):second) time format operators here.
YT shows the same seekbar time format for all languages, and this string is confirming the segment time as it appears in the seekbar. -->
<!-- Shown in the settings preferences, and translations can be any text length. -->
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
@@ -206,6 +205,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">

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