mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-09 10:53:55 +01:00
Compare commits
85 Commits
v4.11.1-de
...
v4.14.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6544cd5fc6 | ||
|
|
4e323aa206 | ||
|
|
c1cee281ff | ||
|
|
0779f9fc5e | ||
|
|
0ee5cf98ab | ||
|
|
6bb848b991 | ||
|
|
188b66ffe7 | ||
|
|
a276425d83 | ||
|
|
e556c3f692 | ||
|
|
cb30248eab | ||
|
|
c5ce742ab4 | ||
|
|
bdd2f7cb0f | ||
|
|
b7600f448d | ||
|
|
5c4bf7676d | ||
|
|
fcd2f9b4c4 | ||
|
|
aa3487aa92 | ||
|
|
ada642f4a7 | ||
|
|
eac758588a | ||
|
|
5d047eae77 | ||
|
|
ed92bf1be6 | ||
|
|
c6318e890f | ||
|
|
7f3b1c54da | ||
|
|
3d0d94b6c8 | ||
|
|
b84e6afebd | ||
|
|
3eab130276 | ||
|
|
95f8e9b3a9 | ||
|
|
d7be94a193 | ||
|
|
e4e20bec6c | ||
|
|
b8bd63a34c | ||
|
|
8b602ca6be | ||
|
|
87eb83607c | ||
|
|
567121d641 | ||
|
|
45e4f70137 | ||
|
|
f814d87c17 | ||
|
|
d0e92b225e | ||
|
|
c64757f80a | ||
|
|
58b6f1fba0 | ||
|
|
630857ba16 | ||
|
|
82ae367946 | ||
|
|
95a7118dcf | ||
|
|
26449cf7c6 | ||
|
|
e4232b6c74 | ||
|
|
1cf25f9dc9 | ||
|
|
8038bd2e98 | ||
|
|
1e81d0c9f8 | ||
|
|
c48cedaddf | ||
|
|
4085d1f9dc | ||
|
|
eadbf5f459 | ||
|
|
b12b3a73a6 | ||
|
|
572a310589 | ||
|
|
2e8d5c61f8 | ||
|
|
025766bb42 | ||
|
|
e31966159a | ||
|
|
337bdc3d39 | ||
|
|
13ed4a2f39 | ||
|
|
d2afc53c2b | ||
|
|
1fab0ae59a | ||
|
|
5c8c597d19 | ||
|
|
33800801a3 | ||
|
|
62c47665e4 | ||
|
|
7acb6cdc96 | ||
|
|
a5d32c3da3 | ||
|
|
a4b0e76755 | ||
|
|
0a7b2c5ec2 | ||
|
|
eed856d64c | ||
|
|
e8d481397f | ||
|
|
d0eceb3e36 | ||
|
|
8886fc4f54 | ||
|
|
fb4256f17c | ||
|
|
98f9bba7ed | ||
|
|
8e72067dcb | ||
|
|
d87f36e7e2 | ||
|
|
4432fe65df | ||
|
|
8b0d8ee9f4 | ||
|
|
250cc7cbde | ||
|
|
1af65de1f6 | ||
|
|
6e87e3044c | ||
|
|
273af26274 | ||
|
|
2b1b081051 | ||
|
|
f2bf2da9a5 | ||
|
|
15317003b1 | ||
|
|
6c81a5b65f | ||
|
|
9ef51abde7 | ||
|
|
1d31565d47 | ||
|
|
b944fb7bf1 |
2
.github/workflows/pull_strings.yml
vendored
2
.github/workflows/pull_strings.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
ref: dev
|
||||
|
||||
- name: Pull strings
|
||||
uses: crowdin/github-action@v1
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
config: crowdin.yml
|
||||
download_translations: true
|
||||
|
||||
2
.github/workflows/push_strings.yml
vendored
2
.github/workflows/push_strings.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Push strings
|
||||
uses: crowdin/github-action@v1
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
config: crowdin.yml
|
||||
upload_sources: true
|
||||
|
||||
267
CHANGELOG.md
267
CHANGELOG.md
@@ -1,3 +1,270 @@
|
||||
# [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)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.11...v4.12.0-dev.12) (2024-07-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.10...v4.12.0-dev.11) (2024-07-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Bypass image region restrictions:** Move setting to `Misc` menu ([094ae59](https://github.com/ReVanced/revanced-patches/commit/094ae59fc92663fff6c5d6f5cbece41822a326f9))
|
||||
|
||||
# [4.12.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.9...v4.12.0-dev.10) (2024-07-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.8...v4.12.0-dev.9) (2024-07-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.7...v4.12.0-dev.8) (2024-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - SponsorBlock:** Correctly show minute timestamp when creating a new segment ([d74c366](https://github.com/ReVanced/revanced-patches/commit/d74c366dbf5f25c20fbfc5a0157c3c15dda82a16))
|
||||
|
||||
# [4.12.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.6...v4.12.0-dev.7) (2024-07-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.5...v4.12.0-dev.6) (2024-07-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Spoof build info` patch ([e7829b4](https://github.com/ReVanced/revanced-patches/commit/e7829b41e782c9feda23b9d6acf48bae277d24d9))
|
||||
|
||||
# [4.12.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.4...v4.12.0-dev.5) (2024-07-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Hide mock location` patch ([#3417](https://github.com/ReVanced/revanced-patches/issues/3417)) ([5f81b40](https://github.com/ReVanced/revanced-patches/commit/5f81b40e7d5567fb5689d08ccc9caeaa267c3143))
|
||||
* **Google Photos:** Add `GmsCore support` patch ([#3414](https://github.com/ReVanced/revanced-patches/issues/3414)) ([24528e0](https://github.com/ReVanced/revanced-patches/commit/24528e0a6eec17ce0a3c52f8862585933615ad28))
|
||||
|
||||
# [4.12.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.3...v4.12.0-dev.4) (2024-07-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.2...v4.12.0-dev.3) (2024-07-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.12.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.12.0-dev.1...v4.12.0-dev.2) (2024-07-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **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.1](https://github.com/ReVanced/revanced-patches/compare/v4.11.1-dev.1...v4.12.0-dev.1) (2024-07-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **SoundCloud:** Add `Enable offline sync` patch ([#3407](https://github.com/ReVanced/revanced-patches/issues/3407)) ([4de86c6](https://github.com/ReVanced/revanced-patches/commit/4de86c6407376bcd3cc0513a2f0707410b8d7ccd))
|
||||
|
||||
## [4.11.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.11.0...v4.11.1-dev.1) (2024-07-12)
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,50 @@ public final class app/revanced/patches/all/interaction/gestures/PredictiveBackG
|
||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/location/hide/HideMockLocationPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/location/hide/HideMockLocationPatch;
|
||||
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 filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Pair;
|
||||
public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V
|
||||
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Pair;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/all/misc/build/BaseSpoofBuildInfoPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
|
||||
public fun <init> ()V
|
||||
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 filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Pair;
|
||||
protected fun getBoard ()Ljava/lang/String;
|
||||
protected fun getBootloader ()Ljava/lang/String;
|
||||
protected fun getBrand ()Ljava/lang/String;
|
||||
protected fun getCpuAbi ()Ljava/lang/String;
|
||||
protected fun getCpuAbi2 ()Ljava/lang/String;
|
||||
protected fun getDevice ()Ljava/lang/String;
|
||||
protected fun getDisplay ()Ljava/lang/String;
|
||||
protected fun getFingerprint ()Ljava/lang/String;
|
||||
protected fun getHardware ()Ljava/lang/String;
|
||||
protected fun getHost ()Ljava/lang/String;
|
||||
protected fun getId ()Ljava/lang/String;
|
||||
protected fun getManufacturer ()Ljava/lang/String;
|
||||
protected fun getModel ()Ljava/lang/String;
|
||||
protected fun getOdmSku ()Ljava/lang/String;
|
||||
protected fun getProduct ()Ljava/lang/String;
|
||||
protected fun getRadio ()Ljava/lang/String;
|
||||
protected fun getSerial ()Ljava/lang/String;
|
||||
protected fun getSku ()Ljava/lang/String;
|
||||
protected fun getSocManufacturer ()Ljava/lang/String;
|
||||
protected fun getSocModel ()Ljava/lang/String;
|
||||
protected fun getTags ()Ljava/lang/String;
|
||||
protected fun getTime ()Ljava/lang/Long;
|
||||
protected fun getType ()Ljava/lang/String;
|
||||
protected fun getUser ()Ljava/lang/String;
|
||||
public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V
|
||||
public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Pair;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/build/SpoofBuildInfoPatch : app/revanced/patches/all/misc/build/BaseSpoofBuildInfoPatch {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
@@ -199,6 +243,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
|
||||
@@ -217,6 +273,46 @@ public final class app/revanced/patches/finanzonline/detection/root/RootDetectio
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/googlenews/customtabs/EnableCustomTabs : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/googlenews/customtabs/EnableCustomTabs;
|
||||
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/googlenews/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/googlenews/misc/gms/GmsCoreSupportPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/googlenews/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/googlenews/misc/gms/GmsCoreSupportResourcePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/googlenews/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
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;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/googlephotos/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/googlephotos/misc/gms/GmsCoreSupportResourcePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/googlephotos/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/googlephotos/misc/integrations/IntegrationsPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -349,6 +445,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
|
||||
@@ -610,6 +712,12 @@ public final class app/revanced/patches/reddit/customclients/baconreader/api/Spo
|
||||
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/boostforreddit/ads/DisableAdsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/ads/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/reddit/customclients/boostforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch;
|
||||
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1050,6 +1158,12 @@ public final class app/revanced/patches/soundcloud/analytics/DisableTelemetryPat
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/soundcloud/offlinesync/EnableOfflineSyncPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/soundcloud/offlinesync/EnableOfflineSyncPatch;
|
||||
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/spotify/layout/theme/CustomThemePatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/spotify/layout/theme/CustomThemePatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
@@ -1098,6 +1212,12 @@ public final class app/revanced/patches/strava/upselling/DisableSubscriptionSugg
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/swissid/integritycheck/RemoveGooglePlayIntegrityCheck : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/swissid/integritycheck/RemoveGooglePlayIntegrityCheck;
|
||||
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/ticktick/misc/themeunlock/UnlockProPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/ticktick/misc/themeunlock/UnlockProPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1718,6 +1838,12 @@ public final class app/revanced/patches/youtube/layout/thumbnails/AlternativeThu
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/layout/thumbnails/BypassImageRegionRestrictions : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/thumbnails/BypassImageRegionRestrictions;
|
||||
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/announcements/AnnouncementsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/announcements/AnnouncementsPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1784,6 +1910,16 @@ public final class app/revanced/patches/youtube/misc/gms/GmsCoreSupportResourceP
|
||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook;
|
||||
public final fun addImageUrlErrorCallbackHook (Ljava/lang/String;)V
|
||||
public final fun addImageUrlHook (Ljava/lang/String;Z)V
|
||||
public static synthetic fun addImageUrlHook$default (Lapp/revanced/patches/youtube/misc/imageurlhook/CronetImageUrlHook;Ljava/lang/String;ZILjava/lang/Object;)V
|
||||
public final fun addImageUrlSuccessCallbackHook (Ljava/lang/String;)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/youtube/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/integrations/IntegrationsPatch;
|
||||
}
|
||||
@@ -1996,6 +2132,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;
|
||||
@@ -2011,7 +2148,11 @@ public final class app/revanced/util/BytecodeUtilsKt {
|
||||
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
|
||||
public static final fun resultOrThrow (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
|
||||
public static final fun returnEarly (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Z)V
|
||||
public static final fun returnEarly (Ljava/lang/Iterable;Z)V
|
||||
public static final fun returnEarly (Ljava/util/List;Z)V
|
||||
public static synthetic fun returnEarly$default (Lapp/revanced/patcher/fingerprint/MethodFingerprint;ZILjava/lang/Object;)V
|
||||
public static synthetic fun returnEarly$default (Ljava/lang/Iterable;ZILjava/lang/Object;)V
|
||||
public static synthetic fun returnEarly$default (Ljava/util/List;ZILjava/lang/Object;)V
|
||||
public static final fun transformMethods (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
|
||||
public static final fun traverseClassHierarchy (Lapp/revanced/patcher/data/BytecodeContext;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
kotlin.code.style = official
|
||||
version = 4.11.1-dev.1
|
||||
version = 4.14.0-dev.2
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
revanced-patcher = "19.3.1"
|
||||
#noinspection GradleDependency
|
||||
smali = "3.0.5" # 3.0.7 breaks binary compatibility. Tracking https://github.com/google/smali/issues/58.
|
||||
guava = "33.1.0-jre"
|
||||
gson = "2.10.1"
|
||||
binary-compatibility-validator = "0.14.0"
|
||||
guava = "33.2.1-jre"
|
||||
gson = "2.11.0"
|
||||
binary-compatibility-validator = "0.15.1"
|
||||
kotlin = "2.0.0"
|
||||
|
||||
[libraries]
|
||||
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
2152
package-lock.json
generated
2152
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.9.1",
|
||||
"semantic-release": "^23.0.8"
|
||||
"gradle-semantic-release-plugin": "^1.9.2",
|
||||
"semantic-release": "^24.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package app.revanced.patches.all.location.hide
|
||||
|
||||
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.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.fromMethodReference
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Patch(
|
||||
name = "Hide mock location",
|
||||
description = "Prevents the app from knowing the device location is being mocked by a third party app.",
|
||||
use = false
|
||||
)
|
||||
object HideMockLocationPatch : BaseTransformInstructionsPatch<Pair<Instruction, Int>>() {
|
||||
override fun filterMap(
|
||||
classDef: ClassDef,
|
||||
method: Method,
|
||||
instruction: Instruction,
|
||||
instructionIndex: Int
|
||||
): Pair<Instruction, Int>? {
|
||||
val reference = instruction.getReference<MethodReference>() ?: return null
|
||||
if (fromMethodReference<MethodCall>(reference) == null) return null
|
||||
|
||||
return instruction to instructionIndex
|
||||
}
|
||||
|
||||
override fun transform(mutableMethod: MutableMethod, entry: Pair<Instruction, Int>) {
|
||||
val (instruction, index) = entry
|
||||
instruction as FiveRegisterInstruction
|
||||
|
||||
// Replace return value with a constant `false` boolean.
|
||||
mutableMethod.replaceInstruction(
|
||||
index + 1,
|
||||
"const/4 v${instruction.registerC}, 0x0"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class MethodCall(
|
||||
override val definedClassName: String,
|
||||
override val methodName: String,
|
||||
override val methodParams: Array<String>,
|
||||
override val returnType: String
|
||||
) : IMethodCall {
|
||||
IsMock("Landroid/location/Location;", "isMock", emptyArray(), "Z"),
|
||||
IsFromMockProvider("Landroid/location/Location;", "isFromMockProvider", emptyArray(), "Z")
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package app.revanced.patches.all.misc.build
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
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.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
abstract class BaseSpoofBuildInfoPatch : BaseTransformInstructionsPatch<Pair<Int, Pair<String, String>>>() {
|
||||
// The build information supported32BitAbis, supported64BitAbis, and supportedAbis are not supported for now,
|
||||
// because initializing an array in transform is a bit more complex.
|
||||
|
||||
protected open val board: String? = null
|
||||
|
||||
protected open val bootloader: String? = null
|
||||
|
||||
protected open val brand: String? = null
|
||||
|
||||
protected open val cpuAbi: String? = null
|
||||
|
||||
protected open val cpuAbi2: String? = null
|
||||
|
||||
protected open val device: String? = null
|
||||
|
||||
protected open val display: String? = null
|
||||
|
||||
protected open val fingerprint: String? = null
|
||||
|
||||
protected open val hardware: String? = null
|
||||
|
||||
protected open val host: String? = null
|
||||
|
||||
protected open val id: String? = null
|
||||
|
||||
protected open val manufacturer: String? = null
|
||||
|
||||
protected open val model: String? = null
|
||||
|
||||
protected open val odmSku: String? = null
|
||||
|
||||
protected open val product: String? = null
|
||||
|
||||
protected open val radio: String? = null
|
||||
|
||||
protected open val serial: String? = null
|
||||
|
||||
protected open val sku: String? = null
|
||||
|
||||
protected open val socManufacturer: String? = null
|
||||
|
||||
protected open val socModel: String? = null
|
||||
|
||||
protected open val tags: String? = null
|
||||
|
||||
protected open val time: Long? = null
|
||||
|
||||
protected open val type: String? = null
|
||||
|
||||
protected open val user: String? = null
|
||||
|
||||
|
||||
// Lazy, so that patch options above are initialized before they are accessed.
|
||||
private val replacements: Map<String, Pair<String, String>> by lazy {
|
||||
buildMap {
|
||||
if (board != null) put("BOARD", "const-string" to "\"$board\"")
|
||||
if (bootloader != null) put("BOOTLOADER", "const-string" to "\"$bootloader\"")
|
||||
if (brand != null) put("BRAND", "const-string" to "\"$brand\"")
|
||||
if (cpuAbi != null) put("CPU_ABI", "const-string" to "\"$cpuAbi\"")
|
||||
if (cpuAbi2 != null) put("CPU_ABI2", "const-string" to "\"$cpuAbi2\"")
|
||||
if (device != null) put("DEVICE", "const-string" to "\"$device\"")
|
||||
if (display != null) put("DISPLAY", "const-string" to "\"$display\"")
|
||||
if (fingerprint != null) put("FINGERPRINT", "const-string" to "\"$fingerprint\"")
|
||||
if (hardware != null) put("HARDWARE", "const-string" to "\"$hardware\"")
|
||||
if (host != null) put("HOST", "const-string" to "\"$host\"")
|
||||
if (id != null) put("ID", "const-string" to "\"$id\"")
|
||||
if (manufacturer != null) put("MANUFACTURER", "const-string" to "\"$manufacturer\"")
|
||||
if (model != null) put("MODEL", "const-string" to "\"$model\"")
|
||||
if (odmSku != null) put("ODM_SKU", "const-string" to "\"$odmSku\"")
|
||||
if (product != null) put("PRODUCT", "const-string" to "\"$product\"")
|
||||
if (radio != null) put("RADIO", "const-string" to "\"$radio\"")
|
||||
if (serial != null) put("SERIAL", "const-string" to "\"$serial\"")
|
||||
if (sku != null) put("SKU", "const-string" to "\"$sku\"")
|
||||
if (socManufacturer != null) put("SOC_MANUFACTURER", "const-string" to "\"$socManufacturer\"")
|
||||
if (socModel != null) put("SOC_MODEL", "const-string" to "\"$socModel\"")
|
||||
if (tags != null) put("TAGS", "const-string" to "\"$tags\"")
|
||||
if (time != null) put("TIME", "const-wide" to "$time")
|
||||
if (type != null) put("TYPE", "const-string" to "\"$type\"")
|
||||
if (user != null) put("USER", "const-string" to "\"$user\"")
|
||||
}
|
||||
}
|
||||
|
||||
override fun filterMap(
|
||||
classDef: ClassDef,
|
||||
method: Method,
|
||||
instruction: Instruction,
|
||||
instructionIndex: Int
|
||||
): Pair<Int, Pair<String, String>>? {
|
||||
val reference = instruction.getReference<FieldReference>() ?: return null
|
||||
if (reference.definingClass != BUILD_CLASS_DESCRIPTOR) return null
|
||||
|
||||
return replacements[reference.name]?.let { instructionIndex to it }
|
||||
}
|
||||
|
||||
override fun transform(mutableMethod: MutableMethod, entry: Pair<Int, Pair<String, String>>) {
|
||||
val (index, replacement) = entry
|
||||
val (opcode, operand) = replacement
|
||||
val register = mutableMethod.getInstruction<OneRegisterInstruction>(index).registerA
|
||||
|
||||
mutableMethod.replaceInstruction(index, "$opcode v$register, $operand")
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val BUILD_CLASS_DESCRIPTOR = "Landroid/os/Build;"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package app.revanced.patches.all.misc.build
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.longPatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||
|
||||
@Patch(
|
||||
name = "Spoof build info",
|
||||
description = "Spoof the information about the current build.",
|
||||
use = false
|
||||
)
|
||||
@Suppress("unused")
|
||||
class SpoofBuildInfoPatch : BaseSpoofBuildInfoPatch() {
|
||||
override val board by stringPatchOption(
|
||||
key = "board",
|
||||
default = null,
|
||||
title = "Board",
|
||||
description = "The name of the underlying board, like \"goldfish\"."
|
||||
)
|
||||
|
||||
override val bootloader by stringPatchOption(
|
||||
key = "bootloader",
|
||||
default = null,
|
||||
title = "Bootloader",
|
||||
description = "The system bootloader version number."
|
||||
)
|
||||
|
||||
override val brand by stringPatchOption(
|
||||
key = "brand",
|
||||
default = null,
|
||||
title = "Brand",
|
||||
description = "The consumer-visible brand with which the product/hardware will be associated, if any."
|
||||
)
|
||||
|
||||
override val cpuAbi by stringPatchOption(
|
||||
key = "cpu-abi",
|
||||
default = null,
|
||||
title = "CPU ABI",
|
||||
description = "This field was deprecated in API level 21. Use SUPPORTED_ABIS instead."
|
||||
)
|
||||
|
||||
override val cpuAbi2 by stringPatchOption(
|
||||
key = "cpu-abi-2",
|
||||
default = null,
|
||||
title = "CPU ABI 2",
|
||||
description = "This field was deprecated in API level 21. Use SUPPORTED_ABIS instead."
|
||||
)
|
||||
|
||||
override val device by stringPatchOption(
|
||||
key = "device",
|
||||
default = null,
|
||||
title = "Device",
|
||||
description = "The name of the industrial design."
|
||||
)
|
||||
|
||||
override val display by stringPatchOption(
|
||||
key = "display",
|
||||
default = null,
|
||||
title = "Display",
|
||||
description = "A build ID string meant for displaying to the user."
|
||||
)
|
||||
|
||||
override val fingerprint by stringPatchOption(
|
||||
key = "fingerprint",
|
||||
default = null,
|
||||
title = "Fingerprint",
|
||||
description = "A string that uniquely identifies this build."
|
||||
)
|
||||
|
||||
override val hardware by stringPatchOption(
|
||||
key = "hardware",
|
||||
default = null,
|
||||
title = "Hardware",
|
||||
description = "The name of the hardware (from the kernel command line or /proc)."
|
||||
)
|
||||
|
||||
override val host by stringPatchOption(
|
||||
key = "host",
|
||||
default = null,
|
||||
title = "Host",
|
||||
description = "The host."
|
||||
)
|
||||
|
||||
override val id by stringPatchOption(
|
||||
key = "id",
|
||||
default = null,
|
||||
title = "ID",
|
||||
description = "Either a changelist number, or a label like \"M4-rc20\"."
|
||||
)
|
||||
|
||||
override val manufacturer by stringPatchOption(
|
||||
key = "manufacturer",
|
||||
default = null,
|
||||
title = "Manufacturer",
|
||||
description = "The manufacturer of the product/hardware."
|
||||
)
|
||||
|
||||
override val model by stringPatchOption(
|
||||
key = "model",
|
||||
default = null,
|
||||
title = "Model",
|
||||
description = "The end-user-visible name for the end product."
|
||||
)
|
||||
|
||||
override val odmSku by stringPatchOption(
|
||||
key = "odm-sku",
|
||||
default = null,
|
||||
title = "ODM SKU",
|
||||
description = "The SKU of the device as set by the original design manufacturer (ODM)."
|
||||
)
|
||||
|
||||
override val product by stringPatchOption(
|
||||
key = "product",
|
||||
default = null,
|
||||
title = "Product",
|
||||
description = "The name of the overall product."
|
||||
)
|
||||
|
||||
override val radio by stringPatchOption(
|
||||
key = "radio",
|
||||
default = null,
|
||||
title = "Radio",
|
||||
description = "This field was deprecated in API level 15. " +
|
||||
"The radio firmware version is frequently not available when this class is initialized, " +
|
||||
"leading to a blank or \"unknown\" value for this string. Use getRadioVersion() instead."
|
||||
)
|
||||
|
||||
override val serial by stringPatchOption(
|
||||
key = "serial",
|
||||
default = null,
|
||||
title = "Serial",
|
||||
description = "This field was deprecated in API level 26. Use getSerial() instead."
|
||||
)
|
||||
|
||||
override val sku by stringPatchOption(
|
||||
key = "sku",
|
||||
default = null,
|
||||
title = "SKU",
|
||||
description = "The SKU of the hardware (from the kernel command line)."
|
||||
)
|
||||
|
||||
override val socManufacturer by stringPatchOption(
|
||||
key = "soc-manufacturer",
|
||||
default = null,
|
||||
title = "SOC Manufacturer",
|
||||
description = "The manufacturer of the device's primary system-on-chip."
|
||||
)
|
||||
|
||||
override val socModel by stringPatchOption(
|
||||
key = "soc-model",
|
||||
default = null,
|
||||
title = "SOC Model",
|
||||
description = "The model name of the device's primary system-on-chip."
|
||||
)
|
||||
|
||||
override val tags by stringPatchOption(
|
||||
key = "tags",
|
||||
default = null,
|
||||
title = "Tags",
|
||||
description = "Comma-separated tags describing the build, like \"unsigned,debug\"."
|
||||
)
|
||||
|
||||
override val time by longPatchOption(
|
||||
key = "time",
|
||||
default = null,
|
||||
title = "Time",
|
||||
description = "The time at which the build was produced, given in milliseconds since the UNIX epoch."
|
||||
)
|
||||
|
||||
override val type by stringPatchOption(
|
||||
key = "type",
|
||||
default = null,
|
||||
title = "Type",
|
||||
description = "The type of build, like \"user\" or \"eng\"."
|
||||
)
|
||||
|
||||
override val user by stringPatchOption(
|
||||
key = "user",
|
||||
default = null,
|
||||
title = "User",
|
||||
description = "The user."
|
||||
)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ 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",
|
||||
"gl-rES" to "gl",
|
||||
"gu-rIN" to "gu",
|
||||
@@ -125,6 +125,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 +139,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",
|
||||
)
|
||||
@@ -347,7 +347,10 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
|
||||
val targetFile =
|
||||
context.get("res/$value/$resourceFileName.xml").also {
|
||||
it.parentFile?.mkdirs()
|
||||
it.createNewFile()
|
||||
|
||||
if(it.createNewFile()) {
|
||||
it.writeText("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>")
|
||||
}
|
||||
}
|
||||
|
||||
context.xmlEditor[targetFile.path].let { editor ->
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
package app.revanced.patches.googlenews.customtabs
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
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.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.googlenews.customtabs.fingerprints.LaunchCustomTabFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
name = "Enable CustomTabs",
|
||||
description = "Enables CustomTabs to open articles in your default browser.",
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.apps.magazines")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object EnableCustomTabs : BytecodePatch(
|
||||
setOf(LaunchCustomTabFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
LaunchCustomTabFingerprint.resultOrThrow().let { result ->
|
||||
result.mutableMethod.apply {
|
||||
val checkIndex = result.scanResult.patternScanResult!!.endIndex + 1
|
||||
val register = getInstruction<OneRegisterInstruction>(checkIndex).registerA
|
||||
|
||||
replaceInstruction(checkIndex, "const/4 v$register, 0x1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package app.revanced.patches.googlenews.customtabs.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 LaunchCustomTabFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
opcodes = listOf(
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IPUT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
),
|
||||
customFingerprint = { _, classDef -> classDef.endsWith("CustomTabsArticleLauncher;") },
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
package app.revanced.patches.googlenews.misc.gms
|
||||
|
||||
internal object Constants {
|
||||
const val MAGAZINES_PACKAGE_NAME = "com.google.android.apps.magazines"
|
||||
const val REVANCED_MAGAZINES_PACKAGE_NAME = "app.revanced.android.magazines"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package app.revanced.patches.googlenews.misc.gms
|
||||
|
||||
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
|
||||
import app.revanced.patches.googlenews.misc.gms.Constants.REVANCED_MAGAZINES_PACKAGE_NAME
|
||||
import app.revanced.patches.googlenews.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
||||
import app.revanced.patches.googlenews.misc.gms.fingerprints.MagazinesActivityOnCreateFingerprint
|
||||
import app.revanced.patches.googlenews.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
||||
|
||||
@Suppress("unused")
|
||||
object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
fromPackageName = MAGAZINES_PACKAGE_NAME,
|
||||
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
||||
primeMethodFingerprint = null,
|
||||
mainActivityOnCreateFingerprint = MagazinesActivityOnCreateFingerprint,
|
||||
integrationsPatchDependency = IntegrationsPatch::class,
|
||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
||||
// Remove version constraint,
|
||||
// once https://github.com/ReVanced/revanced-patches/pull/3111#issuecomment-2240877277 is resolved.
|
||||
compatiblePackages = setOf(CompatiblePackage(MAGAZINES_PACKAGE_NAME, setOf("5.108.0.644447823"))),
|
||||
) {
|
||||
override val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.googlenews.misc.gms
|
||||
|
||||
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
|
||||
import app.revanced.patches.googlenews.misc.gms.Constants.REVANCED_MAGAZINES_PACKAGE_NAME
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch
|
||||
|
||||
object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch(
|
||||
fromPackageName = MAGAZINES_PACKAGE_NAME,
|
||||
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
|
||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.patches.googlenews.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object MagazinesActivityOnCreateFingerprint : MethodFingerprint(
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.googlenews.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object PrimeMethodFingerprint : MethodFingerprint(
|
||||
strings = listOf("com.google.android.GoogleCamera", "com.android.vending"),
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.googlenews.misc.integrations
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.googlenews.misc.integrations.fingerprints.StartActivityInitFingerprint
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
|
||||
@Patch(requiresIntegrations = true)
|
||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||
setOf(StartActivityInitFingerprint),
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
package app.revanced.patches.googlenews.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.googlenews.misc.integrations.fingerprints.StartActivityInitFingerprint.getApplicationContextIndex
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal object StartActivityInitFingerprint : IntegrationsFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.INVOKE_VIRTUAL, // Calls startActivity.getApplicationContext().
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
),
|
||||
insertIndexResolver = { method ->
|
||||
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.name == "getApplicationContext"
|
||||
}
|
||||
|
||||
getApplicationContextIndex + 2 // Below the move-result-object instruction.
|
||||
},
|
||||
contextRegisterResolver = { method ->
|
||||
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
|
||||
as OneRegisterInstruction
|
||||
moveResultInstruction.registerA
|
||||
},
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
|
||||
},
|
||||
) {
|
||||
private var getApplicationContextIndex = -1
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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\"",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"),
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
package app.revanced.patches.googlephotos.misc.gms
|
||||
|
||||
internal object Constants {
|
||||
const val PHOTOS_PACKAGE_NAME = "com.google.android.apps.photos"
|
||||
const val REVANCED_PHOTOS_PACKAGE_NAME = "app.revanced.android.photos"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package app.revanced.patches.googlephotos.misc.gms
|
||||
|
||||
import app.revanced.patches.googlephotos.misc.gms.Constants.PHOTOS_PACKAGE_NAME
|
||||
import app.revanced.patches.googlephotos.misc.gms.Constants.REVANCED_PHOTOS_PACKAGE_NAME
|
||||
import app.revanced.patches.googlephotos.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
||||
import app.revanced.patches.googlephotos.misc.gms.fingerprints.PhotosActivityOnCreateFingerprint
|
||||
import app.revanced.patches.googlephotos.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
||||
|
||||
@Suppress("unused")
|
||||
object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
fromPackageName = PHOTOS_PACKAGE_NAME,
|
||||
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
|
||||
primeMethodFingerprint = null,
|
||||
mainActivityOnCreateFingerprint = PhotosActivityOnCreateFingerprint,
|
||||
integrationsPatchDependency = IntegrationsPatch::class,
|
||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
||||
compatiblePackages = setOf(CompatiblePackage(PHOTOS_PACKAGE_NAME)),
|
||||
) {
|
||||
override val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.googlephotos.misc.gms
|
||||
|
||||
import app.revanced.patches.googlephotos.misc.gms.Constants.PHOTOS_PACKAGE_NAME
|
||||
import app.revanced.patches.googlephotos.misc.gms.Constants.REVANCED_PHOTOS_PACKAGE_NAME
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch
|
||||
|
||||
object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch(
|
||||
fromPackageName = PHOTOS_PACKAGE_NAME,
|
||||
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
|
||||
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600",
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.patches.googlephotos.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object PhotosActivityOnCreateFingerprint : MethodFingerprint(
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;")
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.googlephotos.misc.integrations
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.googlephotos.misc.integrations.fingerprints.HomeActivityInitFingerprint
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
|
||||
@Patch(requiresIntegrations = true)
|
||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||
setOf(HomeActivityInitFingerprint),
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.googlephotos.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.googlephotos.misc.integrations.fingerprints.HomeActivityInitFingerprint.getApplicationContextIndex
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal object HomeActivityInitFingerprint : IntegrationsFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.INVOKE_VIRTUAL, // Calls getApplicationContext().
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
),
|
||||
insertIndexResolver = { method ->
|
||||
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
|
||||
getReference<MethodReference>()?.name == "getApplicationContext"
|
||||
}
|
||||
|
||||
getApplicationContextIndex + 2 // Below the move-result-object instruction.
|
||||
},
|
||||
contextRegisterResolver = { method ->
|
||||
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
|
||||
as OneRegisterInstruction
|
||||
moveResultInstruction.registerA
|
||||
},
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;")
|
||||
},
|
||||
) {
|
||||
private var getApplicationContextIndex = -1
|
||||
}
|
||||
@@ -12,15 +12,15 @@ import app.revanced.util.returnEarly
|
||||
@Patch(
|
||||
name = "Remove root detection",
|
||||
description = "Removes the check for root permissions and unlocked bootloader.",
|
||||
compatiblePackages = [CompatiblePackage("at.gv.oe.app")]
|
||||
compatiblePackages = [CompatiblePackage("at.gv.oe.app")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object RootDetectionPatch : BytecodePatch(
|
||||
setOf(AttestationSupportedCheckFingerprint, BootloaderCheckFingerprint, RootCheckFingerprint)
|
||||
setOf(AttestationSupportedCheckFingerprint, BootloaderCheckFingerprint, RootCheckFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) = listOf(
|
||||
override fun execute(context: BytecodeContext) = setOf(
|
||||
AttestationSupportedCheckFingerprint,
|
||||
BootloaderCheckFingerprint,
|
||||
RootCheckFingerprint
|
||||
RootCheckFingerprint,
|
||||
).returnEarly(true)
|
||||
}
|
||||
|
||||
@@ -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")],
|
||||
)
|
||||
|
||||
@@ -2,16 +2,13 @@ package app.revanced.patches.instagram.patches.ad.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object AdInjectorFingerprint : MethodFingerprint(
|
||||
returnType = "Z",
|
||||
accessFlags = AccessFlags.PRIVATE.value,
|
||||
parameters = listOf("L", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
strings = listOf(
|
||||
"SponsoredContentController.insertItem",
|
||||
"SponsoredContentController::Delivery",
|
||||
),
|
||||
strings = listOf("SponsoredContentController::Delivery"),
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ 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",
|
||||
@@ -25,24 +26,32 @@ import app.revanced.util.exception
|
||||
],
|
||||
)
|
||||
@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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
@@ -3,7 +3,9 @@ package app.revanced.patches.music.misc.gms
|
||||
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
|
||||
import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||
import app.revanced.patches.music.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
||||
import app.revanced.patches.music.misc.gms.fingerprints.*
|
||||
import app.revanced.patches.music.misc.gms.fingerprints.CastDynamiteModuleV2Fingerprint
|
||||
import app.revanced.patches.music.misc.gms.fingerprints.MusicActivityOnCreateFingerprint
|
||||
import app.revanced.patches.music.misc.gms.fingerprints.PrimeMethodFingerprint
|
||||
import app.revanced.patches.music.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
|
||||
@@ -14,9 +16,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
|
||||
primeMethodFingerprint = PrimeMethodFingerprint,
|
||||
earlyReturnFingerprints = setOf(
|
||||
ServiceCheckFingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
CastContextFetchFingerprint,
|
||||
),
|
||||
@@ -32,13 +31,10 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
"7.01.53",
|
||||
"7.02.52",
|
||||
"7.03.52",
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
fingerprints = setOf(
|
||||
ServiceCheckFingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
CastContextFetchFingerprint,
|
||||
PrimeMethodFingerprint,
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.music.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object GooglePlayUtilityFingerprint : MethodFingerprint(
|
||||
"I",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
listOf("L", "I"),
|
||||
strings = listOf(
|
||||
"This should never happen.",
|
||||
"MetadataValueReader",
|
||||
"GooglePlayServicesUtil",
|
||||
"com.android.vending",
|
||||
"android.hardware.type.embedded"
|
||||
)
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.music.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object ServiceCheckFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
listOf("L", "I"),
|
||||
strings = listOf("Google Play Services not available"),
|
||||
)
|
||||
@@ -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(
|
||||
|
||||
@@ -15,5 +15,5 @@ abstract class BaseDisableAdsPatch(
|
||||
compatiblePackages = compatiblePackages,
|
||||
fingerprints = setOf(IsAdsEnabledFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) = listOf(IsAdsEnabledFingerprint).returnEarly()
|
||||
override fun execute(context: BytecodeContext) = IsAdsEnabledFingerprint.returnEarly()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.ads
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.ads.fingerprints.*
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
name = "Disable ads",
|
||||
compatiblePackages = [CompatiblePackage("com.rubenmayayo.reddit")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object DisableAdsPatch : BytecodePatch(
|
||||
setOf(MaxMediationFingerprint, AdmobMediationFingerprint),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) =
|
||||
arrayOf(MaxMediationFingerprint, AdmobMediationFingerprint).forEach {
|
||||
it.resultOrThrow().mutableMethod.addInstructions(0, "return-void")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object AdmobMediationFingerprint : MethodFingerprint(
|
||||
strings = listOf("AdmobMediation: Attempting to initialize SDK")
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object MaxMediationFingerprint : MethodFingerprint(
|
||||
strings = listOf("MaxMediation: Attempting to initialize SDK")
|
||||
)
|
||||
@@ -22,5 +22,5 @@ object UnlockSubscriptionPatch : BytecodePatch(
|
||||
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) =
|
||||
listOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
|
||||
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
) {
|
||||
|
||||
@@ -11,15 +11,20 @@ import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.ACTIONS
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.AUTHORITIES
|
||||
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.PERMISSIONS
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.CastDynamiteModuleFingerprint
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint.GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME
|
||||
import app.revanced.patches.shared.misc.gms.fingerprints.GooglePlayUtilityFingerprint
|
||||
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
|
||||
@@ -42,8 +47,8 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
abstract class BaseGmsCoreSupportPatch(
|
||||
private val fromPackageName: String,
|
||||
private val toPackageName: String,
|
||||
private val primeMethodFingerprint: MethodFingerprint,
|
||||
private val earlyReturnFingerprints: Set<MethodFingerprint>,
|
||||
private val primeMethodFingerprint: MethodFingerprint?,
|
||||
private val earlyReturnFingerprints: Set<MethodFingerprint> = setOf(),
|
||||
private val mainActivityOnCreateFingerprint: MethodFingerprint,
|
||||
private val integrationsPatchDependency: PatchClass,
|
||||
gmsCoreSupportResourcePatch: BaseGmsCoreSupportResourcePatch,
|
||||
@@ -62,6 +67,9 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
compatiblePackages = compatiblePackages,
|
||||
fingerprints = setOf(
|
||||
GmsCoreSupportFingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
ServiceCheckFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
mainActivityOnCreateFingerprint,
|
||||
) + fingerprints,
|
||||
requiresIntegrations = true,
|
||||
@@ -91,17 +99,36 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
}
|
||||
|
||||
// Specific method that needs to be patched.
|
||||
transformPrimeMethod(packageName)
|
||||
primeMethodFingerprint?.let { transformPrimeMethod(packageName) }
|
||||
|
||||
// Return these methods early to prevent the app from crashing.
|
||||
earlyReturnFingerprints.toList().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;->" +
|
||||
"checkGmsCore(Landroid/app/Activity;)V",
|
||||
) ?: throw mainActivityOnCreateFingerprint.exception
|
||||
mainActivityOnCreateFingerprint.result?.mutableMethod?.apply {
|
||||
// Temporary fix for Google photos integration.
|
||||
var 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
|
||||
|
||||
// Change the vendor of GmsCore in ReVanced Integrations.
|
||||
GmsCoreSupportFingerprint.result?.mutableClass?.methods
|
||||
@@ -192,7 +219,7 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
}
|
||||
|
||||
private fun transformPrimeMethod(packageName: String) {
|
||||
primeMethodFingerprint.result?.mutableMethod?.apply {
|
||||
primeMethodFingerprint!!.result?.mutableMethod?.apply {
|
||||
var register = 2
|
||||
|
||||
val index = getInstructions().indexOfFirst {
|
||||
@@ -305,6 +332,7 @@ abstract class BaseGmsCoreSupportPatch(
|
||||
"com.google.android.gms.languageprofile.service.START",
|
||||
"com.google.android.gms.clearcut.service.START",
|
||||
"com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE",
|
||||
"com.google.android.gms.accountsettings.action.VIEW_SETTINGS",
|
||||
|
||||
// potoken
|
||||
"com.google.android.gms.potokens.service.START",
|
||||
|
||||
@@ -96,27 +96,23 @@ abstract class BaseGmsCoreSupportResourcePatch(
|
||||
private fun ResourceContext.patchManifest() {
|
||||
val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName)
|
||||
|
||||
val manifest = this.get("AndroidManifest.xml").readText()
|
||||
this.get("AndroidManifest.xml").writeText(
|
||||
manifest.replace(
|
||||
"package=\"$fromPackageName",
|
||||
"package=\"$packageName",
|
||||
).replace(
|
||||
"android:authorities=\"$fromPackageName",
|
||||
"android:authorities=\"$packageName",
|
||||
).replace(
|
||||
"$fromPackageName.permission.C2D_MESSAGE",
|
||||
"$packageName.permission.C2D_MESSAGE",
|
||||
).replace(
|
||||
"$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
||||
"$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
||||
).replace(
|
||||
"com.google.android.c2dm",
|
||||
"$gmsCoreVendorGroupId.android.c2dm",
|
||||
).replace(
|
||||
"</queries>",
|
||||
"<package android:name=\"$gmsCoreVendorGroupId.android.gms\"/></queries>",
|
||||
),
|
||||
val transformations = mapOf(
|
||||
"package=\"$fromPackageName" to "package=\"$packageName",
|
||||
"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 "$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>",
|
||||
)
|
||||
|
||||
get("AndroidManifest.xml", false).writeText(
|
||||
transformations.entries.fold(get("AndroidManifest.xml", false).readText()) { acc, (from, to) ->
|
||||
acc.replace(
|
||||
from,
|
||||
to,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.music.misc.gms.fingerprints
|
||||
package app.revanced.patches.shared.misc.gms.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.gms.fingerprints
|
||||
package app.revanced.patches.shared.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -8,5 +8,5 @@ internal object GooglePlayUtilityFingerprint : MethodFingerprint(
|
||||
returnType = "I",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("L", "I"),
|
||||
strings = listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms")
|
||||
)
|
||||
strings = listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms"),
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.gms.fingerprints
|
||||
package app.revanced.patches.shared.misc.gms.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -8,5 +8,5 @@ internal object ServiceCheckFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("L", "I"),
|
||||
strings = listOf("Google Play Services not available", "GooglePlayServices not available due to error ")
|
||||
)
|
||||
strings = listOf("Google Play Services not available")
|
||||
)
|
||||
@@ -10,7 +10,7 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.soundcloud.ad.fingerprints.InterceptFingerprint
|
||||
import app.revanced.patches.soundcloud.ad.fingerprints.FeatureConstructorFingerprint
|
||||
import app.revanced.patches.soundcloud.shared.fingerprints.FeatureConstructorFingerprint
|
||||
import app.revanced.patches.soundcloud.ad.fingerprints.UserConsumerPlanConstructorFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package app.revanced.patches.soundcloud.offlinesync
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.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.util.smali.ExternalLabel
|
||||
import app.revanced.patches.soundcloud.offlinesync.fingerprints.DownloadOperationsHeaderVerificationFingerprint
|
||||
import app.revanced.patches.soundcloud.offlinesync.fingerprints.DownloadOperationsURLBuilderFingerprint
|
||||
import app.revanced.patches.soundcloud.shared.fingerprints.FeatureConstructorFingerprint
|
||||
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.FieldReference
|
||||
|
||||
@Patch(
|
||||
name = "Enable offline sync",
|
||||
compatiblePackages = [CompatiblePackage("com.soundcloud.android")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object EnableOfflineSyncPatch : BytecodePatch(
|
||||
setOf(
|
||||
FeatureConstructorFingerprint, DownloadOperationsURLBuilderFingerprint,
|
||||
DownloadOperationsHeaderVerificationFingerprint
|
||||
),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
// Enable the feature to allow offline track syncing by modifying the JSON server response.
|
||||
// This method is the constructor of a class representing a "Feature" object parsed from JSON data.
|
||||
// p1 is the name of the feature.
|
||||
// p2 is true if the feature is enabled, false otherwise.
|
||||
FeatureConstructorFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val afterCheckNotNullIndex = 2
|
||||
|
||||
addInstructionsWithLabels(
|
||||
afterCheckNotNullIndex,
|
||||
"""
|
||||
const-string v0, "offline_sync"
|
||||
invoke-virtual { p1, v0 }, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
|
||||
move-result v0
|
||||
if-eqz v0, :skip
|
||||
const/4 p2, 0x1
|
||||
""",
|
||||
ExternalLabel("skip", getInstruction(afterCheckNotNullIndex)),
|
||||
)
|
||||
}
|
||||
|
||||
// Patch the URL builder to use the HTTPS_STREAM endpoint
|
||||
// instead of the offline sync endpoint to downloading the track.
|
||||
DownloadOperationsURLBuilderFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val getEndpointsEnumFieldIndex = 1
|
||||
val getEndpointsEnumFieldInstruction = getInstruction<OneRegisterInstruction>(getEndpointsEnumFieldIndex)
|
||||
|
||||
val targetRegister = getEndpointsEnumFieldInstruction.registerA
|
||||
val endpointsType = getEndpointsEnumFieldInstruction.getReference<FieldReference>()!!.type
|
||||
|
||||
replaceInstruction(
|
||||
getEndpointsEnumFieldIndex,
|
||||
"sget-object v$targetRegister, $endpointsType->HTTPS_STREAM:$endpointsType"
|
||||
)
|
||||
}
|
||||
|
||||
// The HTTPS_STREAM endpoint does not return the necessary headers for offline sync.
|
||||
// Mock the headers to prevent the app from crashing by setting them to empty strings.
|
||||
// The headers are all cosmetic and do not affect the functionality of the app.
|
||||
DownloadOperationsHeaderVerificationFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
// The first three null checks need to be patched.
|
||||
getInstructions().asSequence().filter {
|
||||
it.opcode == Opcode.IF_EQZ
|
||||
}.take(3).toList().map { it.location.index }.asReversed().forEach { nullCheckIndex ->
|
||||
val headerStringRegister = getInstruction<OneRegisterInstruction>(nullCheckIndex).registerA
|
||||
|
||||
addInstruction(nullCheckIndex, "const-string v$headerStringRegister, \"\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package app.revanced.patches.soundcloud.offlinesync.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 DownloadOperationsHeaderVerificationFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L","L"),
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_STRING
|
||||
),
|
||||
customFingerprint = { _, classDef ->
|
||||
classDef.sourceFile == "DownloadOperations.kt"
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.soundcloud.offlinesync.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 DownloadOperationsURLBuilderFingerprint : MethodFingerprint(
|
||||
returnType = "Ljava/lang/String",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L","L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.FILLED_NEW_ARRAY
|
||||
),
|
||||
customFingerprint = { _, classDef ->
|
||||
classDef.sourceFile == "DownloadOperations.kt"
|
||||
}
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.soundcloud.ad.fingerprints
|
||||
package app.revanced.patches.soundcloud.shared.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.swissid.integritycheck
|
||||
|
||||
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.swissid.integritycheck.fingerprints.CheckIntegrityFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
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")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object RemoveGooglePlayIntegrityCheck : BytecodePatch(
|
||||
setOf(CheckIntegrityFingerprint),
|
||||
) {
|
||||
private const val RESULT_METHOD_REFERENCE = " Lcom/swisssign/deviceintegrity/" +
|
||||
"DeviceintegrityPlugin\$onMethodCall\$1;->\$result:" +
|
||||
"Lio/flutter/plugin/common/MethodChannel\$Result;"
|
||||
private const val SUCCESS_METHOD_REFERENCE =
|
||||
"Lio/flutter/plugin/common/MethodChannel\$Result;->success(Ljava/lang/Object;)V"
|
||||
|
||||
override fun execute(context: BytecodeContext) =
|
||||
CheckIntegrityFingerprint.resultOrThrow().mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
iget-object p1, p0, $RESULT_METHOD_REFERENCE
|
||||
const-string v0, "VALID"
|
||||
invoke-interface {p1, v0}, $SUCCESS_METHOD_REFERENCE
|
||||
return-void
|
||||
""",
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.swissid.integritycheck.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object CheckIntegrityFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("Lcom/swisssign/deviceintegrity/model/DeviceIntegrityResult;"),
|
||||
strings = listOf("it", "result")
|
||||
)
|
||||
@@ -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"),
|
||||
),
|
||||
|
||||
@@ -1,36 +1,18 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails
|
||||
|
||||
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.getInstructions
|
||||
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.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.ListPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.MessageDigestImageUrlFingerprint
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.MessageDigestImageUrlParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.RequestFingerprint
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback.OnFailureFingerprint
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback.OnResponseStartedFingerprint
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback.OnSucceededFingerprint
|
||||
import app.revanced.patches.youtube.misc.imageurlhook.CronetImageUrlHook
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
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.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
|
||||
@Patch(
|
||||
name = "Alternative thumbnails",
|
||||
@@ -39,7 +21,8 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
NavigationBarHookPatch::class
|
||||
NavigationBarHookPatch::class,
|
||||
CronetImageUrlHook::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
@@ -74,65 +57,10 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object AlternativeThumbnailsPatch : BytecodePatch(
|
||||
setOf(
|
||||
MessageDigestImageUrlParentFingerprint,
|
||||
OnResponseStartedFingerprint,
|
||||
RequestFingerprint,
|
||||
),
|
||||
) {
|
||||
object AlternativeThumbnailsPatch : BytecodePatch(emptySet()) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch;"
|
||||
|
||||
private lateinit var loadImageUrlMethod: MutableMethod
|
||||
private var loadImageUrlIndex = 0
|
||||
|
||||
private lateinit var loadImageSuccessCallbackMethod: MutableMethod
|
||||
private var loadImageSuccessCallbackIndex = 0
|
||||
|
||||
private lateinit var loadImageErrorCallbackMethod: MutableMethod
|
||||
private var loadImageErrorCallbackIndex = 0
|
||||
|
||||
/**
|
||||
* @param highPriority If the hook should be called before all other hooks.
|
||||
*/
|
||||
@Suppress("SameParameterValue")
|
||||
private fun addImageUrlHook(targetMethodClass: String, highPriority: Boolean) {
|
||||
loadImageUrlMethod.addInstructions(
|
||||
if (highPriority) 0 else loadImageUrlIndex,
|
||||
"""
|
||||
invoke-static { p1 }, $targetMethodClass->overrideImageURL(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object p1
|
||||
""",
|
||||
)
|
||||
loadImageUrlIndex += 2
|
||||
}
|
||||
|
||||
/**
|
||||
* If a connection completed, which includes normal 200 responses but also includes
|
||||
* status 404 and other error like http responses.
|
||||
*/
|
||||
@Suppress("SameParameterValue")
|
||||
private fun addImageUrlSuccessCallbackHook(targetMethodClass: String) {
|
||||
loadImageSuccessCallbackMethod.addInstruction(
|
||||
loadImageSuccessCallbackIndex++,
|
||||
"invoke-static { p1, p2 }, $targetMethodClass->handleCronetSuccess(" +
|
||||
"Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;)V",
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* If a connection outright failed to complete any connection.
|
||||
*/
|
||||
@Suppress("SameParameterValue")
|
||||
private fun addImageUrlErrorCallbackHook(targetMethodClass: String) {
|
||||
loadImageErrorCallbackMethod.addInstruction(
|
||||
loadImageErrorCallbackIndex++,
|
||||
"invoke-static { p1, p2, p3 }, $targetMethodClass->handleCronetFailure(" +
|
||||
"Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;Ljava/io/IOException;)V",
|
||||
)
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
@@ -177,62 +105,8 @@ object AlternativeThumbnailsPatch : BytecodePatch(
|
||||
ListPreference("revanced_alt_thumbnail_stills_time", summaryKey = null)
|
||||
)
|
||||
|
||||
fun MethodFingerprint.alsoResolve(fingerprint: MethodFingerprint) =
|
||||
also { resolve(context, fingerprint.resultOrThrow().classDef) }.resultOrThrow()
|
||||
|
||||
fun MethodFingerprint.resolveAndLetMutableMethod(
|
||||
fingerprint: MethodFingerprint,
|
||||
block: (MutableMethod) -> Unit,
|
||||
) = alsoResolve(fingerprint).also { block(it.mutableMethod) }
|
||||
|
||||
MessageDigestImageUrlFingerprint.resolveAndLetMutableMethod(MessageDigestImageUrlParentFingerprint) {
|
||||
loadImageUrlMethod = it
|
||||
addImageUrlHook(INTEGRATIONS_CLASS_DESCRIPTOR, true)
|
||||
}
|
||||
|
||||
OnSucceededFingerprint.resolveAndLetMutableMethod(OnResponseStartedFingerprint) {
|
||||
loadImageSuccessCallbackMethod = it
|
||||
addImageUrlSuccessCallbackHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
|
||||
OnFailureFingerprint.resolveAndLetMutableMethod(OnResponseStartedFingerprint) {
|
||||
loadImageErrorCallbackMethod = it
|
||||
addImageUrlErrorCallbackHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
|
||||
// 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.
|
||||
RequestFingerprint.resultOrThrow().apply {
|
||||
// The url is the only string field that is set inside the constructor.
|
||||
val urlFieldInstruction = mutableMethod.getInstructions().first {
|
||||
if (it.opcode != Opcode.IPUT_OBJECT) return@first false
|
||||
|
||||
val reference = (it as ReferenceInstruction).reference as FieldReference
|
||||
reference.type == "Ljava/lang/String;"
|
||||
} as ReferenceInstruction
|
||||
|
||||
val urlFieldName = (urlFieldInstruction.reference as FieldReference).name
|
||||
val definingClass = RequestFingerprint.IMPLEMENTATION_CLASS_NAME
|
||||
val addedMethodName = "getHookedUrl"
|
||||
mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
addedMethodName,
|
||||
emptyList(),
|
||||
"Ljava/lang/String;",
|
||||
AccessFlags.PUBLIC.value,
|
||||
null,
|
||||
null,
|
||||
MutableMethodImplementation(2),
|
||||
).toMutable().apply {
|
||||
addInstructions(
|
||||
"""
|
||||
iget-object v0, p0, $definingClass->$urlFieldName:Ljava/lang/String;
|
||||
return-object v0
|
||||
""",
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
CronetImageUrlHook.addImageUrlHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
CronetImageUrlHook.addImageUrlSuccessCallbackHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
CronetImageUrlHook.addImageUrlErrorCallbackHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
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.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.imageurlhook.CronetImageUrlHook
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
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 " +
|
||||
"and can fix missing images that are blocked in some countries.",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
CronetImageUrlHook::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")
|
||||
object BypassImageRegionRestrictions : BytecodePatch(emptySet()) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/BypassImageRegionRestrictionsPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
SwitchPreference("revanced_bypass_image_region_restrictions")
|
||||
)
|
||||
|
||||
// A priority hook is not needed, as the image urls of interest are not modified
|
||||
// by AlternativeThumbnails or any other patch in this repo.
|
||||
CronetImageUrlHook.addImageUrlHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ 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
|
||||
@@ -13,9 +14,13 @@ 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.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.backgroundplayback.BackgroundPlaybackPatch
|
||||
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.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
@@ -37,16 +42,21 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
UserAgentClientSpoofPatch::class,
|
||||
// Required since iOS livestream fix partially enables background playback.
|
||||
BackgroundPlaybackPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
// This patch works with these versions,
|
||||
// but the dependent background playback patch does not.
|
||||
// "18.37.36",
|
||||
// "18.38.44",
|
||||
// "18.43.45",
|
||||
// "18.44.41",
|
||||
// "18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
@@ -77,18 +87,29 @@ object SpoofClientPatch : BytecodePatch(
|
||||
SetPlayerRequestClientTypeFingerprint,
|
||||
CreatePlayerRequestBodyFingerprint,
|
||||
CreatePlayerRequestBodyWithModelFingerprint,
|
||||
CreatePlayerRequestBodyWithVersionReleaseFingerprint,
|
||||
|
||||
// Player gesture config.
|
||||
PlayerGestureConfigSyntheticFingerprint,
|
||||
|
||||
// Player speed menu item.
|
||||
CreatePlaybackSpeedMenuItemFingerprint,
|
||||
),
|
||||
|
||||
// Video qualities missing.
|
||||
BuildRequestFingerprint,
|
||||
|
||||
// Livestream audio only background playback.
|
||||
PlayerResponseModelBackgroundAudioPlaybackFingerprint,
|
||||
)
|
||||
) {
|
||||
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)
|
||||
@@ -99,9 +120,16 @@ object SpoofClientPatch : BytecodePatch(
|
||||
sorting = PreferenceScreen.Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_spoof_client"),
|
||||
SwitchPreference("revanced_spoof_client_use_ios"),
|
||||
),
|
||||
),
|
||||
ListPreference("revanced_spoof_client_type",
|
||||
summaryKey = null,
|
||||
entriesKey = "revanced_spoof_client_type_entries",
|
||||
entryValuesKey = "revanced_spoof_client_type_entry_values"
|
||||
),
|
||||
SwitchPreference("revanced_spoof_client_ios_force_avc"),
|
||||
NonInteractivePreference("revanced_spoof_client_about_android_ios"),
|
||||
NonInteractivePreference("revanced_spoof_client_about_android_vr")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// region Block /initplayback requests to fall back to /get_watch requests.
|
||||
@@ -153,7 +181,7 @@ object SpoofClientPatch : BytecodePatch(
|
||||
.getInstructions().find { instruction ->
|
||||
// requestMessage.clientInfo = clientInfoBuilder.build();
|
||||
instruction.opcode == Opcode.IPUT_OBJECT &&
|
||||
instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
|
||||
|
||||
// Client info object's client type field.
|
||||
@@ -164,13 +192,15 @@ object SpoofClientPatch : BytecodePatch(
|
||||
// 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")
|
||||
.getReference<FieldReference>()
|
||||
?: throw PatchException("Could not find clientInfoClientVersionField")
|
||||
|
||||
Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
|
||||
}
|
||||
|
||||
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
|
||||
val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
|
||||
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) {
|
||||
@@ -181,6 +211,19 @@ object SpoofClientPatch : BytecodePatch(
|
||||
?: 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.
|
||||
@@ -198,7 +241,7 @@ object SpoofClientPatch : BytecodePatch(
|
||||
addInstruction(
|
||||
checkCastIndex + 1,
|
||||
"invoke-static { v$requestMessageInstanceRegister }," +
|
||||
" ${result.classDef.type}->$setClientInfoMethodName($clientInfoContainerClassName)V",
|
||||
" ${result.classDef.type}->$setClientInfoMethodName($clientInfoContainerClassName)V",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -240,6 +283,12 @@ object SpoofClientPatch : BytecodePatch(
|
||||
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
|
||||
@@ -283,6 +332,23 @@ object SpoofClientPatch : BytecodePatch(
|
||||
|
||||
// endregion
|
||||
|
||||
// region Fix livestream audio only background play if spoofing to iOS.
|
||||
// This force enables audio background playback.
|
||||
|
||||
PlayerResponseModelBackgroundAudioPlaybackFingerprint.resultOrThrow().mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideBackgroundAudioPlayback()Z
|
||||
move-result v0
|
||||
if-eqz v0, :do_not_override
|
||||
return v0
|
||||
:do_not_override
|
||||
nop
|
||||
"""
|
||||
)
|
||||
|
||||
// endregion
|
||||
|
||||
// Fix playback speed menu item if spoofing to iOS.
|
||||
|
||||
CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let {
|
||||
@@ -291,7 +357,8 @@ object SpoofClientPatch : BytecodePatch(
|
||||
|
||||
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 shouldCreateMenuIndex =
|
||||
indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
|
||||
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
@@ -305,5 +372,28 @@ object SpoofClientPatch : BytecodePatch(
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
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;"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
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 PlayerResponseModelBackgroundAudioPlaybackFingerprint : MethodFingerprint(
|
||||
returnType = "Z",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"),
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.GOTO,
|
||||
Opcode.RETURN,
|
||||
null, // Opcode.CONST_4 or Opcode.MOVE
|
||||
Opcode.RETURN,
|
||||
)
|
||||
)
|
||||
@@ -7,7 +7,8 @@ import app.revanced.patches.youtube.misc.fix.playback.SpoofClientPatch
|
||||
import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
|
||||
import app.revanced.patches.youtube.misc.gms.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.gms.fingerprints.CastDynamiteModuleV2Fingerprint
|
||||
import app.revanced.patches.youtube.misc.gms.fingerprints.PrimeMethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.shared.fingerprints.MainActivityOnCreateFingerprint
|
||||
|
||||
@@ -17,9 +18,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME,
|
||||
primeMethodFingerprint = PrimeMethodFingerprint,
|
||||
earlyReturnFingerprints = setOf(
|
||||
ServiceCheckFingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
CastContextFetchFingerprint,
|
||||
),
|
||||
@@ -34,11 +32,12 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
setOf(
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
// Patch supports these versions but ClientSpoof does not.
|
||||
// "18.37.36",
|
||||
// "18.38.44",
|
||||
// "18.43.45",
|
||||
// "18.44.41",
|
||||
// "18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
@@ -61,9 +60,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
),
|
||||
),
|
||||
fingerprints = setOf(
|
||||
ServiceCheckFingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
CastContextFetchFingerprint,
|
||||
PrimeMethodFingerprint,
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.gms.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object CastDynamiteModuleFingerprint : MethodFingerprint(
|
||||
strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl")
|
||||
)
|
||||
@@ -0,0 +1,132 @@
|
||||
package app.revanced.patches.youtube.misc.imageurlhook
|
||||
|
||||
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.getInstructions
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.youtube.misc.imageurlhook.fingerprints.MessageDigestImageUrlFingerprint
|
||||
import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.MessageDigestImageUrlParentFingerprint
|
||||
import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.RequestFingerprint
|
||||
import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.request.callback.OnFailureFingerprint
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
|
||||
@Patch(
|
||||
description = "Hooks Cronet image urls",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class
|
||||
]
|
||||
)
|
||||
object CronetImageUrlHook : BytecodePatch(
|
||||
setOf(
|
||||
MessageDigestImageUrlParentFingerprint,
|
||||
OnResponseStartedFingerprint,
|
||||
RequestFingerprint
|
||||
)
|
||||
) {
|
||||
private lateinit var loadImageUrlMethod: MutableMethod
|
||||
private var loadImageUrlIndex = 0
|
||||
|
||||
private lateinit var loadImageSuccessCallbackMethod: MutableMethod
|
||||
private var loadImageSuccessCallbackIndex = 0
|
||||
|
||||
private lateinit var loadImageErrorCallbackMethod: MutableMethod
|
||||
private var loadImageErrorCallbackIndex = 0
|
||||
|
||||
/**
|
||||
* @param highPriority If the hook should be called before all other hooks.
|
||||
*/
|
||||
fun addImageUrlHook(targetMethodClass: String, highPriority: Boolean = false) {
|
||||
loadImageUrlMethod.addInstructions(
|
||||
if (highPriority) 0 else loadImageUrlIndex,
|
||||
"""
|
||||
invoke-static { p1 }, $targetMethodClass->overrideImageURL(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object p1
|
||||
""",
|
||||
)
|
||||
loadImageUrlIndex += 2
|
||||
}
|
||||
|
||||
/**
|
||||
* If a connection completed, which includes normal 200 responses but also includes
|
||||
* status 404 and other error like http responses.
|
||||
*/
|
||||
fun addImageUrlSuccessCallbackHook(targetMethodClass: String) {
|
||||
loadImageSuccessCallbackMethod.addInstruction(
|
||||
loadImageSuccessCallbackIndex++,
|
||||
"invoke-static { p1, p2 }, $targetMethodClass->handleCronetSuccess(" +
|
||||
"Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;)V",
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* If a connection outright failed to complete any connection.
|
||||
*/
|
||||
fun addImageUrlErrorCallbackHook(targetMethodClass: String) {
|
||||
loadImageErrorCallbackMethod.addInstruction(
|
||||
loadImageErrorCallbackIndex++,
|
||||
"invoke-static { p1, p2, p3 }, $targetMethodClass->handleCronetFailure(" +
|
||||
"Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;Ljava/io/IOException;)V",
|
||||
)
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
loadImageUrlMethod = MessageDigestImageUrlFingerprint
|
||||
.alsoResolve(context, MessageDigestImageUrlParentFingerprint).mutableMethod
|
||||
|
||||
loadImageSuccessCallbackMethod = OnSucceededFingerprint
|
||||
.alsoResolve(context, OnResponseStartedFingerprint).mutableMethod
|
||||
|
||||
loadImageErrorCallbackMethod = OnFailureFingerprint
|
||||
.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.
|
||||
RequestFingerprint.resultOrThrow().apply {
|
||||
// The url is the only string field that is set inside the constructor.
|
||||
val urlFieldInstruction = mutableMethod.getInstructions().single {
|
||||
if (it.opcode != Opcode.IPUT_OBJECT) return@single false
|
||||
|
||||
val reference = (it as ReferenceInstruction).reference as FieldReference
|
||||
reference.type == "Ljava/lang/String;"
|
||||
} as ReferenceInstruction
|
||||
|
||||
val urlFieldName = (urlFieldInstruction.reference as FieldReference).name
|
||||
val definingClass = RequestFingerprint.IMPLEMENTATION_CLASS_NAME
|
||||
val addedMethodName = "getHookedUrl"
|
||||
mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
addedMethodName,
|
||||
emptyList(),
|
||||
"Ljava/lang/String;",
|
||||
AccessFlags.PUBLIC.value,
|
||||
null,
|
||||
null,
|
||||
MutableMethodImplementation(2),
|
||||
).toMutable().apply {
|
||||
addInstructions(
|
||||
"""
|
||||
iget-object v0, p0, $definingClass->$urlFieldName:Ljava/lang/String;
|
||||
return-object v0
|
||||
""",
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails.fingerprints
|
||||
package app.revanced.patches.youtube.misc.imageurlhook.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails.fingerprints
|
||||
package app.revanced.patches.youtube.misc.imageurlhook.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -1,8 +1,8 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet
|
||||
package app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.RequestFingerprint.IMPLEMENTATION_CLASS_NAME
|
||||
import app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.RequestFingerprint.IMPLEMENTATION_CLASS_NAME
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object RequestFingerprint : MethodFingerprint(
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback
|
||||
package app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.request.callback
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback
|
||||
package app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.request.callback
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback
|
||||
package app.revanced.patches.youtube.misc.imageurlhook.fingerprints.cronet.request.callback
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -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")
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -114,7 +114,7 @@ fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementati
|
||||
*
|
||||
* @return the first literal instruction with the value, or throws [PatchException] if not found.
|
||||
*/
|
||||
fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long) : Int {
|
||||
fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long): Int {
|
||||
val index = indexOfFirstWideLiteralInstructionValue(literal)
|
||||
if (index < 0) throw PatchException("Could not find literal value: $literal")
|
||||
return index
|
||||
@@ -160,7 +160,7 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
|
||||
// TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
|
||||
// Method is deprecated, but annotation is commented out otherwise during compilation usage of the replacement is
|
||||
// incorrectly flagged as deprecated.
|
||||
//@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
|
||||
// @Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
|
||||
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
|
||||
|
||||
/**
|
||||
@@ -211,28 +211,47 @@ fun Method.findOpcodeIndicesReversed(opcode: Opcode): List<Int> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved methods of [MethodFingerprint]s early.
|
||||
* Return the resolved method early.
|
||||
*/
|
||||
fun List<MethodFingerprint>.returnEarly(bool: Boolean = false) {
|
||||
fun MethodFingerprint.returnEarly(bool: Boolean = false) {
|
||||
val const = if (bool) "0x1" else "0x0"
|
||||
this.forEach { fingerprint ->
|
||||
fingerprint.result?.let { result ->
|
||||
val stringInstructions = when (result.method.returnType.first()) {
|
||||
'L' ->
|
||||
"""
|
||||
result?.let { result ->
|
||||
val stringInstructions = when (result.method.returnType.first()) {
|
||||
'L' ->
|
||||
"""
|
||||
const/4 v0, $const
|
||||
return-object v0
|
||||
"""
|
||||
'V' -> "return-void"
|
||||
'I', 'Z' ->
|
||||
"""
|
||||
'V' -> "return-void"
|
||||
'I', 'Z' ->
|
||||
"""
|
||||
const/4 v0, $const
|
||||
return v0
|
||||
"""
|
||||
else -> throw Exception("This case should never happen.")
|
||||
}
|
||||
else -> throw Exception("This case should never happen.")
|
||||
}
|
||||
|
||||
result.mutableMethod.addInstructions(0, stringInstructions)
|
||||
} ?: throw fingerprint.exception
|
||||
}
|
||||
result.mutableMethod.addInstructions(0, stringInstructions)
|
||||
} ?: throw exception
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved methods early.
|
||||
*/
|
||||
fun Iterable<MethodFingerprint>.returnEarly(bool: Boolean = false) = forEach { fingerprint ->
|
||||
fingerprint.returnEarly(bool)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved methods early.
|
||||
*/
|
||||
@Deprecated("Use the Iterable version")
|
||||
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()
|
||||
|
||||
@@ -171,10 +171,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. -->
|
||||
<!-- 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">
|
||||
@@ -198,6 +194,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeResourcePatch">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<!-- 'Subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
@@ -206,6 +204,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">
|
||||
|
||||
@@ -171,10 +171,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. -->
|
||||
<!-- 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">
|
||||
@@ -198,6 +194,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeResourcePatch">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<!-- 'Subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
@@ -206,6 +204,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">
|
||||
|
||||
@@ -211,6 +211,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>
|
||||
@@ -246,7 +249,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<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_broad">الكلمة الرئيسية \'%s\' سوف تخفي جميع الفيديوهات</string>
|
||||
</patch>
|
||||
<patch id="ad.general.HideAdsResourcePatch">
|
||||
<string name="revanced_hide_general_ads_title">إخفاء الإعلانات العامة</string>
|
||||
@@ -771,6 +774,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>
|
||||
@@ -864,17 +868,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">مقطع مانِع رُعَاة جديد</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_mark_time_as_question">تعيين %1$02d:%2$02d:%3$03d كبداية أم نهاية لمقطع جديد؟</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\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>
|
||||
@@ -925,7 +925,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 - استعادة سرعة الفيديو الواسعة & قائمة الجودة</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>
|
||||
@@ -990,6 +990,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_seekbar_custom_color_value_summary">لون شريط التقدم</string>
|
||||
<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. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">علامة تبويب الصفحة الرئيسية</string>
|
||||
@@ -1030,6 +1035,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">لم يتم حفظ سجل المشاهدة الخاص بك.<br><br>من المرجح أن يكون السبب في ذلك هو مانع إعلانات DNS أو وكيل الشبكة.<br><br>لإصلاح هذه المشكلة، قم بإضافة <b>s.youtube.com</b> إلى القائمة البيضاء أو قم بإيقاف تشغيل جميع أدوات حظر 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>
|
||||
@@ -1111,9 +1121,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• قد تكون جودة الفيديو الأعلى مفقودة\n• لا يمكن تشغيل البث المباشر كصوت فقط\n• البث المباشر غير متوفر على Android 8.0</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_off">تتم محاكاة العميل حاليًا إلى Android 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>
|
||||
|
||||
@@ -171,10 +171,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. -->
|
||||
<!-- 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">
|
||||
@@ -198,6 +194,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeResourcePatch">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<!-- 'Subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
@@ -206,6 +204,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">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -211,6 +211,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>
|
||||
@@ -246,7 +249,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<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_broad">Ключавое слова \"%s\" схавае ўсе відэа</string>
|
||||
</patch>
|
||||
<patch id="ad.general.HideAdsResourcePatch">
|
||||
<string name="revanced_hide_general_ads_title">Схаваць агульную рэкламу</string>
|
||||
@@ -864,17 +867,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>
|
||||
<!-- 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_mark_time_as_question">Усталяваць %1$02d:%2$02d:%3$03d у якасці пачатку або канца новага сегмента?</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>
|
||||
@@ -990,6 +989,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_seekbar_custom_color_value_summary">Колер панэлі пошуку</string>
|
||||
<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. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">Галоўная ўкладка</string>
|
||||
@@ -1030,6 +1034,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>
|
||||
@@ -1111,9 +1119,6 @@ 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_use_ios_summary_on">Кліент зараз падроблены на iOS\n\nПабочныя эфекты ўключаюць:\n• Няма HDR-відэа\n• Гісторыя праглядаў можа не працаваць\n• Можа адсутнічаць больш высокая якасць відэа\n• Жывыя трансляцыі не могуць прайгравацца толькі як аўдыя\n• Жывая трансляцыя патокі недаступныя на Android 8.0</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_off">Кліент у цяперашні час падроблены для Android VR\n\nПабочныя эфекты ўключаюць:\n• Няма 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>
|
||||
@@ -1162,6 +1167,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_twitch_debug_mode_summary_off">Рэжым адладкі Twitch адключаны</string>
|
||||
</patch>
|
||||
<patch id="misc.settings.SettingsPatch">
|
||||
<string name="revanced_settings">Налады ReVanced</string>
|
||||
<string name="revanced_ads_screen_title">Аб\"явы</string>
|
||||
<string name="revanced_ads_screen_summary">Налады блакіроўкі рэкламы</string>
|
||||
<string name="revanced_chat_screen_title">Чат</string>
|
||||
|
||||
@@ -45,12 +45,20 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</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. -->
|
||||
<string name="gms_core_toast_not_installed_message">GmsCore не е инсталиран. Инсталирайте го.</string>
|
||||
<string name="gms_core_dialog_title">Нужно е действие</string>
|
||||
<string name="gms_core_dialog_not_whitelisted_not_allowed_in_background_message">MicroG GmsCore не може да работи във фонов режим.\n\nМоля, следвайте ръководството \"Don\'t kill my app“ за вашия телефон и приложете инструкциите на MicroG.\n\nТова е необходимо, за да работи приложението.</string>
|
||||
<string name="gms_core_dialog_open_website_text">Отвори сайта</string>
|
||||
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">За да избегнете проблеми е необходимо да изключите оптимизацията на батерията за GmsCore.\n\nНатиснете \"Продолжи\" и изкючере оптимизацията на батерията.</string>
|
||||
<string name="gms_core_dialog_continue_text">Продължи</string>
|
||||
</patch>
|
||||
</app>
|
||||
<app id="youtube">
|
||||
<patch id="misc.settings.SettingsResourcePatch">
|
||||
<string name="revanced_settings_about_links_body">Вие използвате версията на ReVanced Patches<i>%s</i></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>
|
||||
@@ -62,7 +70,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_settings_screen_04_player_title">Плейър</string>
|
||||
<string name="revanced_settings_screen_05_general_title">Общо оформление</string>
|
||||
<string name="revanced_settings_screen_06_shorts_title">Shorts</string>
|
||||
<string name="revanced_settings_screen_07_seekbar_title">Seekbar</string>
|
||||
<string name="revanced_settings_screen_07_seekbar_title">Лента за прогрес на видеото</string>
|
||||
<string name="revanced_settings_screen_08_swipe_controls_title">Контроли с плъзгане</string>
|
||||
<string name="revanced_settings_screen_11_misc_title">Разни</string>
|
||||
<string name="revanced_settings_screen_12_video_title">Видео</string>
|
||||
@@ -85,28 +93,39 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_debug_toast_on_error_user_dialog_message">Ако изключите системните съобщения, ще скриете всички уведомления за ReVanced грешки. \n\nНяма да бъдете уведомени, ако настъпят неочаквани събития.</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.general.HideLayoutComponentsPatch">
|
||||
<string name="revanced_disable_like_subscribe_glow_title">Деактивирайте подсветката на бутона Харесвам /Абонамент</string>
|
||||
<string name="revanced_disable_like_subscribe_glow_summary_on">Бутоните „Харесвам“ и „Абониране“ няма да светят, когато бъдат натиснати</string>
|
||||
<string name="revanced_disable_like_subscribe_glow_summary_off">Бутоните „Харесвам“ и „Абониране“ ще светят, когато бъдат натиснати</string>
|
||||
<string name="revanced_hide_gray_separator_title">Скриване на сивия разделител</string>
|
||||
<string name="revanced_hide_gray_separator_summary_on">Сивите разделители са скрити</string>
|
||||
<string name="revanced_hide_gray_separator_summary_off">Сивите разделители са показани</string>
|
||||
<string name="revanced_hide_channel_watermark_title">Скриване на водния знак на канала</string>
|
||||
<string name="revanced_hide_channel_watermark_summary_on">Водният знак е скрит</string>
|
||||
<string name="revanced_hide_channel_watermark_summary_off">Водният знак е показан</string>
|
||||
<string name="revanced_hide_horizontal_shelves_title">Хоризонтални секции</string>
|
||||
<string name="revanced_hide_horizontal_shelves_summary_on">Хоризонталните секции са скрити:\n• Извънредни новини\n• Продължете да гледате\n• Разгледайте още канали\n• Пазаруване\n• Гледайте отново</string>
|
||||
<string name="revanced_hide_horizontal_shelves_summary_off">Хоризонтални секции се показват</string>
|
||||
<!-- 'Join' should be translated using the same localized wording YouTube displays.
|
||||
This appears in the video player for certain videos. -->
|
||||
<string name="revanced_hide_join_membership_button_title">Скриване на бутона \'Присъедини се\'</string>
|
||||
<string name="revanced_hide_join_membership_button_summary_on">Бутонът е скрит</string>
|
||||
<string name="revanced_hide_join_membership_button_summary_off">Бутонът е показан</string>
|
||||
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
|
||||
<string name="revanced_hide_for_you_shelf_title">Скриване на секцията \'За вас\' в страницата на канала</string>
|
||||
<string name="revanced_hide_for_you_shelf_summary_on">Рафтът е скрит</string>
|
||||
<string name="revanced_hide_for_you_shelf_summary_off">Рафтът е показан</string>
|
||||
<!-- 'Notify me' should be translated using the same localized wording YouTube displays.
|
||||
This item appear in the subscription feed for future livestreams or unreleased videos. -->
|
||||
<string name="revanced_hide_notify_me_button_title">Скриване на бутона \"Уведоми ме\"</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_on">Бутонът е скрит</string>
|
||||
<string name="revanced_hide_notify_me_button_summary_off">Бутонът е показан</string>
|
||||
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
|
||||
<string name="revanced_hide_search_result_recommendations_title">Скриване на препоръките \'Други харесват също\'</string>
|
||||
<string name="revanced_hide_search_result_recommendations_summary_on">Препоръките са скрити</string>
|
||||
<string name="revanced_hide_search_result_recommendations_summary_off">Препоръките са показани</string>
|
||||
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
|
||||
This button usually appears when searching for a YT creator. -->
|
||||
<string name="revanced_hide_show_more_button_title">Скриване на бутона \"Покажи още\"</string>
|
||||
<string name="revanced_hide_show_more_button_summary_on">Бутонът е скрит</string>
|
||||
<string name="revanced_hide_show_more_button_summary_off">Бутонът е показан</string>
|
||||
<string name="revanced_hide_timed_reactions_title">Скриване на времевите реакции</string>
|
||||
@@ -157,6 +176,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_channel_bar_title">Скриване на лентата на канала</string>
|
||||
<string name="revanced_hide_channel_bar_summary_on">Лентата на канала е скрита</string>
|
||||
<string name="revanced_hide_channel_bar_summary_off">Лентата на канала е показана</string>
|
||||
<string name="revanced_hide_playables_title">Игри в YouTube</string>
|
||||
<string name="revanced_hide_playables_summary_on">Игри в YouTube са скрити</string>
|
||||
<string name="revanced_hide_playables_summary_off">Игрите в YouTube се показват</string>
|
||||
<string name="revanced_hide_quick_actions_title">Скриване на бързите действия в режим на цял екран</string>
|
||||
<string name="revanced_hide_quick_actions_summary_on">Бързите действия в режим на цял екран са скрити</string>
|
||||
<string name="revanced_hide_quick_actions_summary_off">Бързите действия в режим на цял екран са показани</string>
|
||||
@@ -178,9 +200,22 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_chips_shelf_title">Скриване на рафта за чипове</string>
|
||||
<string name="revanced_hide_chips_shelf_summary_on">Рафтът за чипове е скрит</string>
|
||||
<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_chapters_section_title">Скриване на секцията с заглавия</string>
|
||||
<string name="revanced_hide_chapters_section_summary_on">Секцията с заглавия е скрита</string>
|
||||
<string name="revanced_hide_chapters_section_summary_off">Секцията с заглавия се показва</string>
|
||||
<string name="revanced_hide_podcast_section_title">Скриване секцията „Разгледайте подкаста“</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">\"Разгледайте подкаста\" е скрита</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">\"Разгледайте подкаста\" се показва</string>
|
||||
<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>
|
||||
<string name="revanced_hide_description_components_screen_title">Описание на видеото</string>
|
||||
@@ -200,6 +235,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_keyword_content_home_summary_on">Видеоклиповете на началния екран са филтрирани с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_home_summary_off">Видеоклиповете на началния екран не са филтрирани с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_subscriptions_title">Скриване на видеоклипове от абонаменти с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_subscriptions_summary_on">Видеоклиповете в раздела за абонаменти са са филтрирани с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_subscriptions_summary_off">Видеоклиповете в раздела за абонаменти са са филтрирани с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_search_title">Скриване на резултати от търсения с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_search_summary_on">Резултатите от търсения са филтрирани с ключови думи</string>
|
||||
@@ -211,16 +247,24 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_keyword_content_about_title">За филтриране с ключови думи</string>
|
||||
<string name="revanced_hide_keyword_content_about_summary">Начало/Абонамент/Резултатите от търсенето се филтрират, за да се скрие съдържанието, което съответства на ключовите фрази\n\nОграничения\n• Някои кратки видеоклипове може да не са скрити\n• Някои компоненти на потребителския интерфейс може да не са скрити\n• Търсенето на ключова дума може да не покаже резултати</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>
|
||||
</patch>
|
||||
<patch id="ad.general.HideAdsResourcePatch">
|
||||
<string name="revanced_hide_general_ads_title">Скриване на общите реклами</string>
|
||||
<string name="revanced_hide_general_ads_summary_on">Общите реклами са скрити</string>
|
||||
<string name="revanced_hide_general_ads_summary_off">Общите реклами са показани</string>
|
||||
<string name="revanced_hide_fullscreen_ads_title">Скриване на рекламите в режим на цял екран</string>
|
||||
<string name="revanced_hide_fullscreen_ads_summary_on">Рекламите на цял екран са скрити\n\in Тази функция е достъпна само за по-стари устройства</string>
|
||||
<string name="revanced_hide_fullscreen_ads_summary_off">Рекламите в режим на цял екран са показани</string>
|
||||
<string name="revanced_hide_buttoned_ads_title">Скриване на рекламни бутони</string>
|
||||
<string name="revanced_hide_buttoned_ads_summary_on">Рекламите като бутон са скрити</string>
|
||||
<string name="revanced_hide_buttoned_ads_summary_off">Рекламите като бутон са показани</string>
|
||||
<string name="revanced_hide_paid_promotion_label_title">Скриване на платените промоции</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_on">Промоционалните етикети са скрити</string>
|
||||
<string name="revanced_hide_paid_promotion_label_summary_off">Промоционалните етикети се показват</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_title">Скриване на самоспонсорирани карти</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_on">Самоспонсорираните карти са скрити</string>
|
||||
<string name="revanced_hide_self_sponsor_ads_summary_off">Самоспонсорираните карти са показани</string>
|
||||
@@ -231,6 +275,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_shopping_links_summary_on">Връзките за пазаруване са скрити</string>
|
||||
<string name="revanced_hide_shopping_links_summary_off">Връзките за пазаруване са показани</string>
|
||||
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_visit_store_button_title">Скрийте бутона „Посетете магазина“ на страниците на каналите</string>
|
||||
<string name="revanced_hide_visit_store_button_summary_on">Бутонът е скрит</string>
|
||||
<string name="revanced_hide_visit_store_button_summary_off">Бутонът е показан</string>
|
||||
<string name="revanced_hide_web_search_results_title">Скриване на резултатите от уеб търсенето</string>
|
||||
@@ -240,6 +285,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_merchandise_banners_summary_on">Банерите за стоки са скрити</string>
|
||||
<string name="revanced_hide_merchandise_banners_summary_off">Банерите за стоки са показани</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">Скр. на реклами на цял екран, за по-стари устройства</string>
|
||||
</patch>
|
||||
<patch id="ad.getpremium.HideGetPremiumPatch">
|
||||
<string name="revanced_hide_get_premium_title">Скриване на YouTube Premium промоции</string>
|
||||
@@ -255,14 +301,17 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_share_copy_url_success">URL адресът е копиран в клипборда</string>
|
||||
<string name="revanced_share_copy_url_timestamp_success">URL адресът с времеви отпечатък е копиран</string>
|
||||
<string name="revanced_copy_video_url_title">Показване на бутона за копиране на URL адреса на видеоклипа</string>
|
||||
<string name="revanced_copy_video_url_summary_on">Показан е бутон. Докоснете, за да копирате URL на видеото. Докоснете и задръжте, за да копирате URL адреса на видеоклипа с клеймо за време</string>
|
||||
<string name="revanced_copy_video_url_summary_off">Бутонът не е показан</string>
|
||||
<string name="revanced_copy_video_url_timestamp_title">Показване на бутона за копиране на URL адреса на времевия отпечатък на видеоклипа</string>
|
||||
<string name="revanced_copy_video_url_timestamp_summary_on">Показан е бутон. Докоснете, за да копирате URL адреса на видеоклипа с клеймо за време. Докоснете и задръжте, за да копирате видеоклип без клеймо за време</string>
|
||||
<string name="revanced_copy_video_url_timestamp_summary_off">Бутонът не е показан</string>
|
||||
</patch>
|
||||
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
|
||||
<string name="revanced_remove_viewer_discretion_dialog_title">Скриване на прозореца за възрастово ограничение</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_on">Диалоговият прозорец ще бъде премахнат</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary_off">Диалоговият прозорец ще бъде показан</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_user_dialog_message">Тази функция не заобикаля възрастовото ограничение. Тя просто приема възрастовата граница автоматично.</string>
|
||||
</patch>
|
||||
<patch id="interaction.downloads.DownloadsResourcePatch">
|
||||
<string name="revanced_external_downloader_screen_title">Външни изтегляния</string>
|
||||
@@ -276,6 +325,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_external_downloader_action_button_summary_off">Бутонът за изтегляне отваря вграденото приложение за изтегляне</string>
|
||||
<string name="revanced_external_downloader_name_title">Име на пакета на изтеглящото приложение</string>
|
||||
<string name="revanced_external_downloader_name_summary">Име на пакета на приложението за изтегляне, като NewPipe или Seal</string>
|
||||
<string name="revanced_external_downloader_not_installed_warning">%s не е инсталиран. Инсталирайте го.</string>
|
||||
</patch>
|
||||
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
|
||||
<string name="revanced_disable_precise_seeking_gesture_title">Деактивиране на жеста за точно търсене</string>
|
||||
@@ -303,6 +353,10 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_swipe_save_and_restore_brightness_title">Запазване и възстановяване на яркостта</string>
|
||||
<string name="revanced_swipe_save_and_restore_brightness_summary_on">Запазване и възстаовяване яркостта при включване или изключване на цял екран</string>
|
||||
<string name="revanced_swipe_save_and_restore_brightness_summary_off">Не се запазва или възстаовява яркостта при включване или изключване на цял екран</string>
|
||||
<string name="revanced_swipe_lowest_value_enable_auto_brightness_title">Задаване на яркост чрез плъзгане</string>
|
||||
<string name="revanced_swipe_lowest_value_enable_auto_brightness_summary_on">Плъзгането надолу до най-ниската стойност на жеста за яркост, за да се активира автоматичната яркост</string>
|
||||
<string name="revanced_swipe_lowest_value_enable_auto_brightness_summary_off">Плъзгането надолу до най-ниската стойност на жеста за яркост, без дасе активира автоматичната яркост</string>
|
||||
<string name="revanced_swipe_lowest_value_enable_auto_brightness_overlay_text">Авто</string>
|
||||
<string name="revanced_swipe_overlay_timeout_title">Задръжка на плъзгащата контрола</string>
|
||||
<string name="revanced_swipe_overlay_timeout_summary">Време за което плъзгащата контрола е видима</string>
|
||||
<string name="revanced_swipe_text_overlay_size_title">Размер на текста при плъзгане</string>
|
||||
@@ -313,194 +367,763 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_swipe_threshold_summary">Праг преди да се осъществи плъзгането</string>
|
||||
</patch>
|
||||
<patch id="layout.autocaptions.AutoCaptionsPatch">
|
||||
<string name="revanced_auto_captions_title">Автоматични Субтитри</string>
|
||||
<string name="revanced_auto_captions_summary_on">Автоматичните Субтитри са деактивирани</string>
|
||||
<string name="revanced_auto_captions_summary_off">Автоматичните Субтитри са активирани</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.action.HideButtonsPatch">
|
||||
<string name="revanced_hide_buttons_screen_title">Бутони за действия</string>
|
||||
<string name="revanced_hide_buttons_screen_summary">Скриване или показване на бутони под видеото</string>
|
||||
<string name="revanced_hide_like_dislike_button_title">Бутони \"Харесвам\" и \"Не харесвам\"</string>
|
||||
<string name="revanced_hide_like_dislike_button_summary_on">Бутоните \"Харесвам\" и \"Не харесвам\" са скрити</string>
|
||||
<string name="revanced_hide_like_dislike_button_summary_off">Бутоните \"Харесвам\" и \"Не харесвам\" се показват</string>
|
||||
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_share_button_title">Скриване на споделянето</string>
|
||||
<string name="revanced_hide_share_button_summary_on">Бутона за споделяне е скрит</string>
|
||||
<string name="revanced_hide_share_button_summary_off">Бутона за споделяне се показва</string>
|
||||
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
|
||||
This button usually appears only on live streams. -->
|
||||
<string name="revanced_hide_report_button_title">Бутон за доклади</string>
|
||||
<string name="revanced_hide_report_button_summary_on">Бутона за докладване е скрит</string>
|
||||
<string name="revanced_hide_report_button_summary_off">Бутона за докладване се показва</string>
|
||||
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_remix_button_title">Бутон за ремикс</string>
|
||||
<string name="revanced_hide_remix_button_summary_on">Бутона за ремикс е скрит</string>
|
||||
<string name="revanced_hide_remix_button_summary_off">Бутона за ремикс се показва</string>
|
||||
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_download_button_title">Бутон за изтегляне</string>
|
||||
<string name="revanced_hide_download_button_summary_on">Бутона за изтегляне е скрит</string>
|
||||
<string name="revanced_hide_download_button_summary_off">Бутона за изтегляне се показва</string>
|
||||
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_thanks_button_title">Бутон за благодарност</string>
|
||||
<string name="revanced_hide_thanks_button_summary_on">Бутона за благодарност е скрит</string>
|
||||
<string name="revanced_hide_thanks_button_summary_off">Бутона за благодарност се показва</string>
|
||||
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_clip_button_title">Бутон за създаване на клип</string>
|
||||
<string name="revanced_hide_clip_button_summary_on">Бутона за клип е скрит</string>
|
||||
<string name="revanced_hide_clip_button_summary_off">Бутона за клип се показва</string>
|
||||
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
|
||||
<string name="revanced_hide_playlist_button_title">Бутон за Запазване в плейлиста</string>
|
||||
<string name="revanced_hide_playlist_button_summary_on">Бутонът за Запазване в плейлиста е скрит</string>
|
||||
<string name="revanced_hide_playlist_button_summary_off">Бутонът за Запазване в плейлиста се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
|
||||
<string name="revanced_hide_autoplay_button_title">Бутона за авт. изпълнение</string>
|
||||
<string name="revanced_hide_autoplay_button_summary_on">Бутона за авт. изпълнение е скрит</string>
|
||||
<string name="revanced_hide_autoplay_button_summary_off">Бутона за авт. изпълнение се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.captions.HideCaptionsButtonPatch">
|
||||
<!-- This button does not display any text, but 'captions' should be translated using the same wording used as the translation of 'revanced_hide_player_flyout_captions_title' -->
|
||||
<string name="revanced_hide_captions_button_title">Бутона за Субтитри</string>
|
||||
<string name="revanced_hide_captions_button_summary_on">Бутона за субтити е скрит</string>
|
||||
<string name="revanced_hide_captions_button_summary_off">Бутона за субтити се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.cast.HideCastButtonPatch">
|
||||
<string name="revanced_hide_cast_button_title">Бутон за предаване на Тв</string>
|
||||
<string name="revanced_hide_cast_button_summary_on">Бутонът за предаване е скрит</string>
|
||||
<string name="revanced_hide_cast_button_summary_off">Бутонът за предаване се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
|
||||
<string name="revanced_navigation_buttons_screen_title">Бутони за навигация</string>
|
||||
<string name="revanced_navigation_buttons_screen_summary">Скриване или промяна на бутоните в лентата за навигация</string>
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
|
||||
<string name="revanced_hide_home_button_title">Бутон за Начало</string>
|
||||
<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_summary_on">Бутона за кратки клипове е скрит</string>
|
||||
<string name="revanced_hide_shorts_button_summary_off">Бутона за кратки клипове се показва</string>
|
||||
<!-- The Create button has no display name. Translate normally. -->
|
||||
<string name="revanced_hide_create_button_title">Бутон за създаване на клип</string>
|
||||
<string name="revanced_hide_create_button_summary_on">Бутонът за създаване е скрит</string>
|
||||
<string name="revanced_hide_create_button_summary_off">Бутона за създаване се показва</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
|
||||
<string name="revanced_hide_subscriptions_button_title">Абонаменти</string>
|
||||
<string name="revanced_hide_subscriptions_button_summary_on">Бутона за абонаменти е скрит</string>
|
||||
<string name="revanced_hide_subscriptions_button_summary_off">Бутона за абонаменти се показва</string>
|
||||
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
|
||||
<string name="revanced_switch_create_with_notifications_button_title">Заменете бутона „Създаване“ с бутона „Известия“</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_on">Бутонът за създаване се заменя с бутона за известия\n\nЗабележка: Активирането на тази опция също скрива видеореклами</string>
|
||||
<string name="revanced_switch_create_with_notifications_button_summary_off">Бутоните \"Създаване\" и \"Известия\" не са разменени</string>
|
||||
<string name="revanced_hide_navigation_button_labels_title">Имена на бутоните на лентата за навигация</string>
|
||||
<string name="revanced_hide_navigation_button_labels_summary_on">Етикетите са скрити</string>
|
||||
<string name="revanced_hide_navigation_button_labels_summary_off">Етикетите се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
|
||||
<string name="revanced_hide_player_flyout_title">Падащо меню</string>
|
||||
<string name="revanced_hide_player_flyout_summary">Скриване или показване на елементи от падащото меню на плейъра</string>
|
||||
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_captions_title">Меню \"Субтитри\"</string>
|
||||
<string name="revanced_hide_player_flyout_captions_summary_on">Менюто за субтитрие скрито</string>
|
||||
<string name="revanced_hide_player_flyout_captions_summary_off">Менюто за субтитрие се показва</string>
|
||||
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_additional_settings_title">Меню \"Допълнителни настройки\"</string>
|
||||
<string name="revanced_hide_player_flyout_additional_settings_summary_on">Допълнителните настройки са скрити</string>
|
||||
<string name="revanced_hide_player_flyout_additional_settings_summary_off">Допълнителните настройки се показват</string>
|
||||
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_loop_video_title">\"Повторно възпроизвеждане\"</string>
|
||||
<string name="revanced_hide_player_flyout_loop_video_summary_on">Менюто за повторение е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_loop_video_summary_off">Менюто за повторение се показва</string>
|
||||
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_ambient_mode_title">Ambient mode</string>
|
||||
<string name="revanced_hide_player_flyout_ambient_mode_summary_on">Менюто за околен режим е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_ambient_mode_summary_off">Менюто за околен режим се показва</string>
|
||||
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_help_title">Помощ & Отзиви</string>
|
||||
<string name="revanced_hide_player_flyout_help_summary_on">Менюто & за помощ е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_help_summary_off">Менюто & за помощ се показва</string>
|
||||
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_speed_title">Скриване на скоростта на възпроизвеждане</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_on">Менюто за скорост на видеото е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_speed_summary_off">Менюто за скорост на видеото се показва</string>
|
||||
<!-- 'More info' should be translated using the same localized wording YouTube displays for the menu item.
|
||||
This menu only appears for some videos. Translate the name normally if the menu cannot be found. -->
|
||||
<string name="revanced_hide_player_flyout_more_info_title">\"Допълнителна информация\"</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_on">\"Допълнителна информация\" е скрита</string>
|
||||
<string name="revanced_hide_player_flyout_more_info_summary_off">\"Допълнителна информация\" се показва</string>
|
||||
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_lock_screen_title">\"Заключен екран\"</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_on">Менюто на заключен екран е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_lock_screen_summary_off">Менюто на заключен екран се показва</string>
|
||||
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_audio_track_title">Избор на Аудио</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_on">Менюто за избор на Аудио е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_audio_track_summary_off">Менюто за избор на Аудио се показва</string>
|
||||
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_title">Гледайте във VR</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_on">Менюто за гледане в VR е скрито</string>
|
||||
<string name="revanced_hide_player_flyout_watch_in_vr_summary_off">Менюто за гледане в VR се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
|
||||
<string name="revanced_hide_player_buttons_title">Бутони за Предишно & Следващо видео</string>
|
||||
<string name="revanced_hide_player_buttons_summary_on">Бутоните са скрити</string>
|
||||
<string name="revanced_hide_player_buttons_summary_off">Бутоните се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
|
||||
<string name="revanced_hide_album_cards_title">\"Карти на албумите\"</string>
|
||||
<string name="revanced_hide_album_cards_summary_on">Албумните карти са скрити</string>
|
||||
<string name="revanced_hide_album_cards_summary_off">Албумните карти се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.comments.CommentsPatch">
|
||||
<string name="revanced_comments_screen_title">Коментари</string>
|
||||
<string name="revanced_comments_screen_summary">Скриване или показване на секцията за коментари</string>
|
||||
<string name="revanced_hide_comments_by_members_header_title">Скриване на „Коментари, направени от членове“</string>
|
||||
<string name="revanced_hide_comments_by_members_header_summary_on">„Коментари от членове“ са скрити</string>
|
||||
<string name="revanced_hide_comments_by_members_header_summary_off">„Коментари от членове“ се показват</string>
|
||||
<string name="revanced_hide_comments_section_title">Скриване на секцията с коментари</string>
|
||||
<string name="revanced_hide_comments_section_summary_on">Секцията с коментари е скрита</string>
|
||||
<string name="revanced_hide_comments_section_summary_off">Секцията с коментари се показва</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_title">Бутон за създаване на Shorts</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_summary_on">Бутон за създаване на Shorts е скрит</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_summary_off">Бутон за създаване на Shorts се показва</string>
|
||||
<string name="revanced_hide_comments_preview_comment_title">Преглед на коментари</string>
|
||||
<string name="revanced_hide_comments_preview_comment_summary_on">Прегледа на коментари е скрит</string>
|
||||
<string name="revanced_hide_comments_preview_comment_summary_off">Прегледа на коментари се показва</string>
|
||||
<string name="revanced_hide_comments_thanks_button_title">Бутон за благодарност</string>
|
||||
<string name="revanced_hide_comments_thanks_button_summary_on">Бутона за благодарност е скрит</string>
|
||||
<string name="revanced_hide_comments_thanks_button_summary_off">Бутона за благодарност се показва</string>
|
||||
<string name="revanced_hide_comments_timestamp_and_emoji_buttons_title">Бутони в лентата на прогреса и емотикони</string>
|
||||
<string name="revanced_hide_comments_timestamp_and_emoji_buttons_summary_on">Бутоните са скрити</string>
|
||||
<string name="revanced_hide_comments_timestamp_and_emoji_buttons_summary_off">Бутоните се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
|
||||
<string name="revanced_hide_crowdfunding_box_title">Дарителска кутия</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_on">Кутията за дарения е скрита</string>
|
||||
<string name="revanced_hide_crowdfunding_box_summary_off">Кутията за дарения се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
|
||||
<string name="revanced_hide_endscreen_cards_title">Скриване на препоръките в края</string>
|
||||
<string name="revanced_hide_endscreen_cards_summary_on">Препоръките в края са скрити</string>
|
||||
<string name="revanced_hide_endscreen_cards_summary_off">Препоръките в края се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
|
||||
<string name="revanced_hide_filter_bar_screen_title">Лента с филтри</string>
|
||||
<string name="revanced_hide_filter_bar_screen_summary">Скриване или показване на лентата с категории в емисията, резултатите от търсенето и свързаните видеоклипове</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_title">Скриване на горната лента с категории в емисията</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_summary_on">Скрита</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_feed_summary_off">Показва се</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_title">Филтъри на търсене</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_summary_on">Панелът с филтъри на търсене е скрит</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_search_summary_off">Панелът с филтъри на търсене се показва</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_title">Скриване в сродни видеоклипове</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_on">Скриване в сродни видеоклипове</string>
|
||||
<string name="revanced_hide_filter_bar_feed_in_related_videos_summary_off">Показано в сродни видеоклипове</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
|
||||
<string name="revanced_hide_floating_microphone_button_title">Плаващ бутон за микрофона</string>
|
||||
<string name="revanced_hide_floating_microphone_button_summary_on">Бутонът на микрофона е скрит</string>
|
||||
<string name="revanced_hide_floating_microphone_button_summary_off">Показан е бутон на микрофона</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
|
||||
<string name="revanced_disable_fullscreen_ambient_mode_title">Деактивирайте околния режим на цял екран</string>
|
||||
<string name="revanced_disable_fullscreen_ambient_mode_summary_on">Подсветката в режим на цял екран е деактивирана</string>
|
||||
<string name="revanced_disable_fullscreen_ambient_mode_summary_off">Подсветката в режим на цял екран е активирана</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
|
||||
<string name="revanced_hide_info_cards_title">Скриване на инфо. карти</string>
|
||||
<string name="revanced_hide_info_cards_summary_on">Информационните карти са скрити</string>
|
||||
<string name="revanced_hide_info_cards_summary_off">Информационните карти се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
|
||||
<string name="revanced_disable_rolling_number_animations_title">Анимация на числа в реално време</string>
|
||||
<string name="revanced_disable_rolling_number_animations_summary_on">Анимацията е деактивирана</string>
|
||||
<string name="revanced_disable_rolling_number_animations_summary_off">Анимацията е активирана</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.seekbar.HideSeekbarPatch">
|
||||
<string name="revanced_hide_seekbar_title">Скриване на лента за време на плейъра</string>
|
||||
<string name="revanced_hide_seekbar_summary_on">Лентата за време на плейъра е скрита</string>
|
||||
<string name="revanced_hide_seekbar_summary_off">Лентата за време на плейъра се показва</string>
|
||||
<string name="revanced_hide_seekbar_thumbnail_title">Скр. лента за време при миниатюрите</string>
|
||||
<string name="revanced_hide_seekbar_thumbnail_summary_on">Лентата за време при миниатюрите е скрита</string>
|
||||
<string name="revanced_hide_seekbar_thumbnail_summary_off">Лентата за време при миниатюрите се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
|
||||
<!-- 'home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<string name="revanced_hide_shorts_home_title">Скриване на Shorts в началната лента</string>
|
||||
<string name="revanced_hide_shorts_home_summary_on">Shorts в началната лента са скрити</string>
|
||||
<string name="revanced_hide_shorts_home_summary_off">Shorts в началната лента са показани</string>
|
||||
<!-- 'subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
<string name="revanced_hide_shorts_subscriptions_title">Shorts в раздел „Абонаменти“</string>
|
||||
<string name="revanced_hide_shorts_subscriptions_summary_on">Shorts в раздел „Абонаменти“ са скрити</string>
|
||||
<string name="revanced_hide_shorts_subscriptions_summary_off">Shorts в раздел „Абонаменти“ се показват</string>
|
||||
<string name="revanced_hide_shorts_search_title">Shorts в резултатите от търсенето</string>
|
||||
<string name="revanced_hide_shorts_search_summary_on">Shorts в резултатите от търсенето са скрити</string>
|
||||
<string name="revanced_hide_shorts_search_summary_off">Shorts в резултатите от търсенето се показват</string>
|
||||
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
|
||||
<string name="revanced_hide_shorts_join_button_title">Бутон за присъединяване</string>
|
||||
<string name="revanced_hide_shorts_join_button_summary_on">Бутона за присъединяване е скрит</string>
|
||||
<string name="revanced_hide_shorts_join_button_summary_off">Бутона за присъединяване се показва</string>
|
||||
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
|
||||
<string name="revanced_hide_shorts_subscribe_button_title">Скрийте бутона „Абониране“</string>
|
||||
<string name="revanced_hide_shorts_subscribe_button_summary_on">Бутонът „Абониране“ е скрит</string>
|
||||
<string name="revanced_hide_shorts_subscribe_button_summary_off">Бутонът „Абониране“ се показва</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_title">Показване на бутони при пауза</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_on">Бутоните при пауза се скриват</string>
|
||||
<string name="revanced_hide_shorts_paused_overlay_buttons_summary_off">Бутоните при пауза се показват</string>
|
||||
<string name="revanced_hide_shorts_shop_button_title">Скриване на бутона за пазаруване</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_on">Бутона за пазаруване е скрит</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_off">Бутона за пазаруване се показва</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_title">Бутон \"Специални благодарности\"</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_on">Бутон \"Специални благодарности\" е скрит</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_off">Бутон \"Специални благодарности\" се показва</string>
|
||||
<string name="revanced_hide_shorts_tagged_products_title">Скриване на маркираните продукти</string>
|
||||
<string name="revanced_hide_shorts_tagged_products_summary_on">Скрити</string>
|
||||
<string name="revanced_hide_shorts_tagged_products_summary_off">Показват се</string>
|
||||
<string name="revanced_hide_shorts_location_label_title">Етикет за местоположение</string>
|
||||
<string name="revanced_hide_shorts_location_label_summary_on">Етикет за местоположение е скрит</string>
|
||||
<string name="revanced_hide_shorts_location_label_summary_off">Етикет за местоположение се показва</string>
|
||||
<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_search_suggestions_title">Скриване на предложенията за търсене</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_summary_on">Предложенията за търсене са скрити</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_summary_off">Предложенията за търсене се показват</string>
|
||||
<string name="revanced_hide_shorts_like_button_title">Скриване на бутона за харесване</string>
|
||||
<string name="revanced_hide_shorts_like_button_summary_on">Бутона за харесване е скрит</string>
|
||||
<string name="revanced_hide_shorts_like_button_summary_off">Бутона за харесване се показва</string>
|
||||
<string name="revanced_hide_shorts_dislike_button_title">Скриване на бутона за нехаресване</string>
|
||||
<string name="revanced_hide_shorts_dislike_button_summary_on">Бутона за нехаресване е скрит</string>
|
||||
<string name="revanced_hide_shorts_dislike_button_summary_off">Бутона за нехаресване се показва</string>
|
||||
<string name="revanced_hide_shorts_comments_button_title">Скриване на бутона за коментари</string>
|
||||
<string name="revanced_hide_shorts_comments_button_summary_on">Бутон за коментари е скрит</string>
|
||||
<string name="revanced_hide_shorts_comments_button_summary_off">Бутон за коментари се показва</string>
|
||||
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
|
||||
<string name="revanced_hide_shorts_remix_button_title">Бутон за ремикс</string>
|
||||
<string name="revanced_hide_shorts_remix_button_summary_on">Бутона за ремикс е скрит</string>
|
||||
<string name="revanced_hide_shorts_remix_button_summary_off">Бутона за ремикс се показва</string>
|
||||
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
|
||||
<string name="revanced_hide_shorts_share_button_title">Бутон за споделяне</string>
|
||||
<string name="revanced_hide_shorts_share_button_summary_on">Бутона за споделяне е скрит</string>
|
||||
<string name="revanced_hide_shorts_share_button_summary_off">Бутона за споделяне се показва</string>
|
||||
<string name="revanced_hide_shorts_info_panel_title">Информационни панели</string>
|
||||
<string name="revanced_hide_shorts_info_panel_summary_on">Информационните панели са скрити</string>
|
||||
<string name="revanced_hide_shorts_info_panel_summary_off">Информационните панели се показват</string>
|
||||
<string name="revanced_hide_shorts_channel_bar_title">Скриване на лентата на канала</string>
|
||||
<string name="revanced_hide_shorts_channel_bar_summary_on">Лентата на канала е скрита</string>
|
||||
<string name="revanced_hide_shorts_channel_bar_summary_off">Лентата на канала е показана</string>
|
||||
<string name="revanced_hide_shorts_video_title_title">Заглавие на видеото</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_on">Заглавието е скрито</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_off">Заглавието се показва</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_title">Скриване на музикални метаданни</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_summary_on">Метаданни са скрити</string>
|
||||
<string name="revanced_hide_shorts_sound_metadata_label_summary_off">Метаданни се показват</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_title">Скриване на етикет за връзка към видеоклипа</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_summary_on">Етикетът за видео връзка е скрит</string>
|
||||
<string name="revanced_hide_shorts_full_video_link_label_summary_off">Етикетът за видео връзка се показва</string>
|
||||
<string name="revanced_hide_shorts_sound_button_title">Скрийте бутона „Звук“</string>
|
||||
<string name="revanced_hide_shorts_sound_button_summary_on">Бутона за Звук е скрит</string>
|
||||
<string name="revanced_hide_shorts_sound_button_summary_off">Бутона за Звук се показва</string>
|
||||
<string name="revanced_hide_shorts_navigation_bar_title">Скриване лентата за навигация</string>
|
||||
<string name="revanced_hide_shorts_navigation_bar_summary_on">Навигационната лента е скрита</string>
|
||||
<string name="revanced_hide_shorts_navigation_bar_summary_off">Навигационната лента се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
|
||||
<string name="revanced_disable_suggested_video_end_screen_title">Препоръчани видеоклипове в края</string>
|
||||
<string name="revanced_disable_suggested_video_end_screen_summary_on">Препоръчаните видеоклипове в края са скрити</string>
|
||||
<string name="revanced_disable_suggested_video_end_screen_summary_off">Препоръчаните видеоклипове в края се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.time.HideTimestampPatch">
|
||||
<string name="revanced_hide_timestamp_title">Скриване на клеймото за време на видеоклипа</string>
|
||||
<string name="revanced_hide_timestamp_summary_on">Скрито</string>
|
||||
<string name="revanced_hide_timestamp_summary_off">Показва се</string>
|
||||
</patch>
|
||||
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
|
||||
<string name="revanced_hide_player_popup_panels_title">Изскачащи панели на плейъра</string>
|
||||
<string name="revanced_hide_player_popup_panels_summary_on">Изскачащите панели на плейъра са скрити</string>
|
||||
<string name="revanced_hide_player_popup_panels_summary_off">Изскачащите панели на плейъра се показват</string>
|
||||
</patch>
|
||||
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
|
||||
<string name="revanced_player_overlay_opacity_title">Прозрачност на настройките в Плеара</string>
|
||||
<string name="revanced_player_overlay_opacity_summary">Стойност на прозрачност между 0-100, където 0 е прозрачно</string>
|
||||
<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 timed out)</string>
|
||||
<string name="revanced_ryd_failure_connection_status_code">Нехаресванията не са налични (status %d)</string>
|
||||
<string name="revanced_ryd_failure_client_rate_limit_requested">Нехаресванията не са достъпни (достигнат лимит на API)</string>
|
||||
<string name="revanced_ryd_failure_generic">Нехаресванията не са налични (%s)</string>
|
||||
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
|
||||
<string name="revanced_ryd_failure_ryd_enabled_while_playing_video_then_user_voted">Презареди видеото за гласуване с ReturnYouTubeDislike</string>
|
||||
<string name="revanced_ryd_enable_summary_on">Нехаресванията се показват</string>
|
||||
<string name="revanced_ryd_enable_summary_off">Нехаресванията не се показват</string>
|
||||
<string name="revanced_ryd_shorts_title">Пок. нехаресвания в кратките клипове</string>
|
||||
<string name="revanced_ryd_shorts_summary_on">Нехаресванията се показват в кратките клипове</string>
|
||||
<string name="revanced_ryd_shorts_summary_on_disclaimer">Нехаресвания, показани в Shorts\n\nОграничение: Нехаресванията може да не се показват в режим „инкогнито“</string>
|
||||
<string name="revanced_ryd_shorts_summary_off">Нехаресванията са скрити в кратките клипове</string>
|
||||
<string name="revanced_ryd_dislike_percentage_title">Нехаресвания като процент</string>
|
||||
<string name="revanced_ryd_dislike_percentage_summary_on">Нехаресванията се показват като процент</string>
|
||||
<string name="revanced_ryd_dislike_percentage_summary_off">Нехаресванията се показват като число</string>
|
||||
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
|
||||
<string name="revanced_ryd_compact_layout_title">Компактен бутон за харесване</string>
|
||||
<string name="revanced_ryd_compact_layout_summary_on">Включен компактен бутон \"Харесва ми\"</string>
|
||||
<string name="revanced_ryd_compact_layout_summary_off">Най-добър изглед на бутона за харесване</string>
|
||||
<string name="revanced_ryd_toast_on_connection_error_title">Показване на известие, ако API не е наличен</string>
|
||||
<string name="revanced_ryd_toast_on_connection_error_summary_on">Показва известие, ако Return YouTube Dislike не е наличен</string>
|
||||
<string name="revanced_ryd_toast_on_connection_error_summary_off">Не се показва известие, ако ReturnYouTube Dislike не е наличен</string>
|
||||
<string name="revanced_ryd_about">Относно</string>
|
||||
<string name="revanced_ryd_attribution_summary">Данните за нехаресване са от Return YouTube Dislike API. Докоснете за да научите повече</string>
|
||||
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
|
||||
<string name="revanced_ryd_statistics_category_title">Статистика Return YouTube Dislike API на това устройство</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallResponseTimeAverage_title">Време за отговор на API, средно</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallResponseTimeMin_title">Време за отговор на API, минимално</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallResponseTimeMax_title">Време за отговор на API, максимално</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallResponseTimeLast_title">Време за отговор на API, последно видео</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallResponseTimeLast_rate_limit_summary">Нехаресванията временно не са налични - в сила е лимитът API клиента</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallCount_title">API получава гласове, брой заявки</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallCount_zero_summary">Неуспешни мрежови заявки</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallCount_non_zero_summary">%d мрежови заявки</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallNumberOfFailures_title">API извлича гласове, брой изчаквания</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallNumberOfFailures_zero_summary">Мрежовите заявки нямаха изчакване</string>
|
||||
<string name="revanced_ryd_statistics_getFetchCallNumberOfFailures_non_zero_summary">%d изтече времето за изчакване на мрежовите повиквания</string>
|
||||
<string name="revanced_ryd_statistics_getNumberOfRateLimitRequestsEncountered_title">Ограничения на скоростта на API клиент</string>
|
||||
<string name="revanced_ryd_statistics_getNumberOfRateLimitRequestsEncountered_zero_summary">Ограниченията на скоростта на клиента на Api не са открити</string>
|
||||
<string name="revanced_ryd_statistics_getNumberOfRateLimitRequestsEncountered_non_zero_summary">Открити са ограничения на скоростта на клиента на Api %d пъти</string>
|
||||
<string name="revanced_ryd_statistics_millisecond_text">%d милисекунди</string>
|
||||
</patch>
|
||||
<patch id="layout.searchbar.WideSearchbarPatch">
|
||||
<string name="revanced_wide_searchbar_title">Широка лента за търсене</string>
|
||||
<string name="revanced_wide_searchbar_summary_on">Широката лента за търсене е включена</string>
|
||||
<string name="revanced_wide_searchbar_summary_off">Широката лента за търсене е изключена</string>
|
||||
</patch>
|
||||
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
|
||||
<string name="revanced_restore_old_seekbar_thumbnails_title">Стари миниатюри на времевата линия</string>
|
||||
<string name="revanced_restore_old_seekbar_thumbnails_summary_on">Над лентата за възпроизвеждане се появяват миниатюри</string>
|
||||
<string name="revanced_restore_old_seekbar_thumbnails_summary_off">Миниатюрите се показват в режим на цял екран</string>
|
||||
</patch>
|
||||
<patch id="layout.sponsorblock.SponsorBlockResourcePatch">
|
||||
<string name="revanced_sb_enable_sb">Включване на SponsorBlock</string>
|
||||
<string name="revanced_sb_enable_sb_sum">SponsorBlock е система за прескачане на досадни части и реклами от видеоклиповете в YouTube</string>
|
||||
<string name="revanced_sb_appearance_category">Облик</string>
|
||||
<string name="revanced_sb_enable_voting">Бутона за гласуване</string>
|
||||
<string name="revanced_sb_enable_voting_sum_on">Бутона за гласуване на част се показва</string>
|
||||
<string name="revanced_sb_enable_voting_sum_off">Бутона за гласуване на част е скрит</string>
|
||||
<!-- Translations should use language similar to 'revanced_ryd_compact_layout_title' -->
|
||||
<string name="revanced_sb_enable_compact_skip_button">Компактен бутон за пропускане</string>
|
||||
<string name="revanced_sb_enable_compact_skip_button_sum_on">Мин. ширина на бутона за пропускане</string>
|
||||
<string name="revanced_sb_enable_compact_skip_button_sum_off">Най-добър изглед на бутона за пропускане</string>
|
||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button">Авт. скриване на бутона за пропускане</string>
|
||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_on">Бутона за пропускане се скрива след няколко секунди</string>
|
||||
<string name="revanced_sb_enable_auto_hide_skip_segment_button_sum_off">Бутона за пропускане се показва за цялата част</string>
|
||||
<string name="revanced_sb_general_skiptoast">Показв. известие при автом. пропуск. част</string>
|
||||
<string name="revanced_sb_general_skiptoast_sum_on">Показване на известие при автоматично пропусната част. Докоснете тук за пример</string>
|
||||
<string name="revanced_sb_general_skiptoast_sum_off">Известието не се показва. Докоснете тук за пример</string>
|
||||
<string name="revanced_sb_general_time_without">Показване на дължината на видеото без сигментите</string>
|
||||
<string name="revanced_sb_general_time_without_sum_on">Дължината на видеото без всички части показана в скоби до цялата дължина</string>
|
||||
<string name="revanced_sb_general_time_without_sum_off">Цялата дължина на видето се показва</string>
|
||||
<string name="revanced_sb_create_segment_category">Създаване на нови части</string>
|
||||
<string name="revanced_sb_enable_create_segment">Показване на бутона за нова част</string>
|
||||
<string name="revanced_sb_enable_create_segment_sum_on">Бутона създаване за нова част се показва</string>
|
||||
<string name="revanced_sb_enable_create_segment_sum_off">Бутона създаване за нова част не се показва</string>
|
||||
<string name="revanced_sb_general_adjusting">Настройване стъпка на новата част</string>
|
||||
<string name="revanced_sb_general_adjusting_sum">Милисекундите с който се преместват бутоните за настройка при създаване на част</string>
|
||||
<string name="revanced_sb_general_adjusting_invalid">Стойността трябва да е положително число</string>
|
||||
<string name="revanced_sb_guidelines_preference_title">Преглед на ръководните линии</string>
|
||||
<string name="revanced_sb_guidelines_preference_sum">Указанията съдържат правила и съвети за създаване на нови части</string>
|
||||
<string name="revanced_sb_guidelines_popup_title">Следвайте указанията</string>
|
||||
<string name="revanced_sb_guidelines_popup_content">Прочетете указанията на SponsorBlock преди да създадете нови части</string>
|
||||
<string name="revanced_sb_guidelines_popup_already_read">Вече прочетох</string>
|
||||
<string name="revanced_sb_guidelines_popup_open">Покажи ми</string>
|
||||
<string name="revanced_sb_general">Общи</string>
|
||||
<string name="revanced_sb_toast_on_connection_error_title">Показване на известие, ако API не е наличен</string>
|
||||
<string name="revanced_sb_toast_on_connection_error_summary_on">Показва се известие, ако SponsorBlock не е наличен</string>
|
||||
<string name="revanced_sb_toast_on_connection_error_summary_off">Показва се известие, ако SponsorBlock не е наличен</string>
|
||||
<string name="revanced_sb_general_skipcount">Прослед. на броя пропускания</string>
|
||||
<string name="revanced_sb_general_skipcount_sum_on">Показва в класацията на SponsorBlock колко време е спестено. Съобщение се изпраща при всяка пропусната част</string>
|
||||
<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">Вашият уникален потребителски id</string>
|
||||
<string name="revanced_sb_general_uuid_sum">Това трябва да се държи тайно. То е като парола и не трябва да се споделя с никого. Ако някой го има, то той може да се представи вместо вас</string>
|
||||
<string name="revanced_sb_general_uuid_invalid">Личният Id трябва да е с дължина поне 30 знака</string>
|
||||
<string name="revanced_sb_general_api_url">Промяна URL на API</string>
|
||||
<string name="revanced_sb_general_api_url_sum">Адресът, който SponsorBlock използва за свързване към сървъра</string>
|
||||
<string name="revanced_sb_api_url_reset">Нулиране URL адреса на API</string>
|
||||
<string name="revanced_sb_api_url_invalid">URL адресът е невалиден</string>
|
||||
<string name="revanced_sb_api_url_changed">URL адресът на API е променен</string>
|
||||
<string name="revanced_sb_settings_ie">Настройки за внасяне и изнасяне</string>
|
||||
<string name="revanced_sb_settings_copy">Копиране</string>
|
||||
<string name="revanced_sb_settings_ie_sum">Вашата JSON конфигурация на SponsorBlock може да бъде импортирана/експортирана в ReVanced и други платформи на SponsorBlock</string>
|
||||
<string name="revanced_sb_settings_ie_sum_warning">Вашата SponsorBlock JSON конфигурация която може да се импортира/експортира до ReVanced или други платформи ползващи SponsorBlock. Това включва вашия потребителски id. Споделяйте това разумно</string>
|
||||
<string name="revanced_sb_settings_import_successful">Настройките са успешно въстановени</string>
|
||||
<string name="revanced_sb_settings_import_failed">Неуспешно импортиране: %s</string>
|
||||
<string name="revanced_sb_settings_export_failed">Неуспешно експортиране на %s</string>
|
||||
<string name="revanced_sb_settings_revanced_export_user_id_warning">Вашите настройки на SponsorBlock съдържат лично Id.\n\nВашето Id е като парола и не трябва да се споделя с никого\n</string>
|
||||
<string name="revanced_sb_settings_revanced_export_user_id_warning_dismiss">Не показвай отново</string>
|
||||
<string name="revanced_sb_diff_segments">Промени поведението на сигмента</string>
|
||||
<string name="revanced_sb_segments_sponsor">Спонсор</string>
|
||||
<string name="revanced_sb_segments_sponsor_sum">Платена промоция, платени препоръки и директни реклами. Не за самореклама или безплатни препоръки за каузи/създатели/уебсайтове/продукти, които се харесват на автора</string>
|
||||
<string name="revanced_sb_segments_selfpromo">Неплатена/Самореклама</string>
|
||||
<string name="revanced_sb_segments_selfpromo_sum">Подобно на „Спонсор“, с изключение на неплатено или самореклама. Включва раздели за стоки, дарения или информация за това с кого са си сътрудничили</string>
|
||||
<string name="revanced_sb_segments_interaction">Напомняне за действие (абониране)</string>
|
||||
<string name="revanced_sb_segments_interaction_sum">Кратко напомняне да харесате, абонирате или последвате в средата на съдържанието. Ако е дълго или за нещо конкретно, вместо това трябва да бъде самореклама</string>
|
||||
<string name="revanced_sb_segments_highlight">Акценти</string>
|
||||
<string name="revanced_sb_segments_highlight_sum">Частта от видеото която повечето хора търсят</string>
|
||||
<string name="revanced_sb_segments_intro">Пауза / Начална анимация</string>
|
||||
<string name="revanced_sb_segments_intro_sum">Интервал без реално съдържание. Може да бъде пауза, статичен кадър, повтаряща се анимация. Това не трябва да се използва за преходи, съдържащи информация</string>
|
||||
<string name="revanced_sb_segments_outro">Карти в края/Пояснения</string>
|
||||
<string name="revanced_sb_segments_outro_sum">Информация или когато се показват крайните карти на YouTube. Не за заключения с информация</string>
|
||||
<string name="revanced_sb_segments_preview">Кратък преглед/Обобщение</string>
|
||||
<string name="revanced_sb_segments_preview_sum">Колекция от клипове, които показват какво предстои в този видеоклип или в други видеоклипове от поредицата, където цялата информация се повтаря по-късно във видеоклипа</string>
|
||||
<string name="revanced_sb_segments_filler">Пълнеж/Шеги</string>
|
||||
<string name="revanced_sb_segments_filler_sum">Сцени извън темата, добавени само за пълнеж или хумор, които не са необходими за разбирането на основното съдържание на видеоклипа. Това не трябва да включва сегменти, предоставящи контекст или справочни данни</string>
|
||||
<string name="revanced_sb_segments_nomusic">Музика: Част без музика</string>
|
||||
<string name="revanced_sb_segments_nomusic_sum">За използване само в музикални видеоклипове. Това трябва да се използва само за части от музикални видеоклипове, които вече не са обхванати от друга категория</string>
|
||||
<string name="revanced_sb_skip_button_compact">Пропусни</string>
|
||||
<string name="revanced_sb_skip_button_compact_highlight">Акценти</string>
|
||||
<string name="revanced_sb_skip_button_sponsor">Пропусни спонсор</string>
|
||||
<string name="revanced_sb_skip_button_selfpromo">Пропусни промоция</string>
|
||||
<string name="revanced_sb_skip_button_interaction">Пропусни подканване</string>
|
||||
<string name="revanced_sb_skip_button_highlight">Пропусни до акценти</string>
|
||||
<string name="revanced_sb_skip_button_intro_beginning">Пропуснете въведението</string>
|
||||
<string name="revanced_sb_skip_button_intro_middle">Пропусни пауза</string>
|
||||
<string name="revanced_sb_skip_button_intro_end">Пропусни пауза</string>
|
||||
<string name="revanced_sb_skip_button_outro">Пропусни заключение</string>
|
||||
<string name="revanced_sb_skip_button_preview_beginning">Пропусни преглед</string>
|
||||
<string name="revanced_sb_skip_button_preview_middle">Пропусни преглед</string>
|
||||
<string name="revanced_sb_skip_button_preview_end">Пропуснете обобщението</string>
|
||||
<string name="revanced_sb_skip_button_filler">Пропусни пълнеж</string>
|
||||
<string name="revanced_sb_skip_button_nomusic">Пропусни част без музика</string>
|
||||
<string name="revanced_sb_skip_button_unsubmitted">Пропускане на сегмент</string>
|
||||
<string name="revanced_sb_skipped_sponsor">Пропуснат спонсор</string>
|
||||
<string name="revanced_sb_skipped_selfpromo">Пропусната самореклама</string>
|
||||
<string name="revanced_sb_skipped_interaction">Пропуснато досадно напомняне</string>
|
||||
<string name="revanced_sb_skipped_highlight">Пропуснато до акцент</string>
|
||||
<string name="revanced_sb_skipped_intro_beginning">Пропуснато въведение</string>
|
||||
<string name="revanced_sb_skipped_intro_middle">Пропусни паузи</string>
|
||||
<string name="revanced_sb_skipped_intro_end">Пропусни паузи</string>
|
||||
<string name="revanced_sb_skipped_outro">Пропуснато заключение</string>
|
||||
<string name="revanced_sb_skipped_preview_beginning">Пропуснат преглед</string>
|
||||
<string name="revanced_sb_skipped_preview_middle">Пропуснат преглед</string>
|
||||
<string name="revanced_sb_skipped_preview_end">Пропуснато повторение</string>
|
||||
<string name="revanced_sb_skipped_filler">Пропуснат пълнеж</string>
|
||||
<string name="revanced_sb_skipped_nomusic">Пропусната част без музика</string>
|
||||
<string name="revanced_sb_skipped_unsubmitted">Пропуснат неизпратен сегмент</string>
|
||||
<string name="revanced_sb_skipped_multiple_segments">Пропуснати множество части</string>
|
||||
<string name="revanced_sb_skip_automatically">Да се прескача от само себе си</string>
|
||||
<string name="revanced_sb_skip_automatically_once">Авт. пропускане веднъж</string>
|
||||
<string name="revanced_sb_skip_showbutton">Показвай бутон за пропускане</string>
|
||||
<string name="revanced_sb_skip_seekbaronly">Показв. в лентата за време</string>
|
||||
<string name="revanced_sb_skip_ignore">Изключване</string>
|
||||
<string name="revanced_sb_submit_failed_invalid">Не може да се изпрати сегмент: %s</string>
|
||||
<string name="revanced_sb_submit_failed_timeout">SponsorBlock временно не работи</string>
|
||||
<string name="revanced_sb_submit_failed_unknown_error">Не могат да се изпратят сигменти: (статус:%1$d %2$s)</string>
|
||||
<string name="revanced_sb_submit_failed_rate_limit">Не може да се изпрати частта.\nБроят е ограничен (Твърде много от един и същ потребител, IP)</string>
|
||||
<string name="revanced_sb_submit_failed_forbidden">Не може да се изпрати частта: %s</string>
|
||||
<string name="revanced_sb_submit_failed_duplicate">Не може да се изпрати частта.\nВече съществува</string>
|
||||
<string name="revanced_sb_submit_succeeded">Частта е изпратена успешно</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_sb_sponsorblock_connection_failure_timeout">SponsorBlock временно не е наличен (API timed out)</string>
|
||||
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlock временно не е наличен (status %d)</string>
|
||||
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlock временно не е наличен</string>
|
||||
<string name="revanced_sb_vote_failed_timeout">Не може да се гласува за сегмент (API timed out)</string>
|
||||
<string name="revanced_sb_vote_failed_unknown_error">Не може да се гласува за частите: (статус: %1$d %2$s)</string>
|
||||
<string name="revanced_sb_vote_failed_forbidden">Не може да се гласува за част: %s</string>
|
||||
<string name="revanced_sb_vote_upvote">Положителен вот</string>
|
||||
<string name="revanced_sb_vote_downvote">Отрицателен вот</string>
|
||||
<string name="revanced_sb_vote_category">Промяна на категорията</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_vote_no_segments">Няма сегменти, за които да гласувате</string>
|
||||
<string name="revanced_sb_new_segment_choose_category">Изберете категория сегмент</string>
|
||||
<string name="revanced_sb_new_segment_disabled_category">Категорията е изкл. в настройките. Вкл. я за да можете да изпратите.</string>
|
||||
<string name="revanced_sb_new_segment_title">Нова част в SponsorBlock</string>
|
||||
<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>
|
||||
<!-- 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_time_start">Частта започва от</string>
|
||||
<string name="revanced_sb_new_segment_time_end">Частта свършва до</string>
|
||||
<string name="revanced_sb_new_segment_confirm_title">Времената точни ли са?</string>
|
||||
<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>
|
||||
<string name="revanced_sb_new_segment_preview_segment_first">Преглед и проверка на частта за нормално пропускане</string>
|
||||
<string name="revanced_sb_new_segment_edit_by_hand_title">Ръчно редактиране на времената на частта</string>
|
||||
<string name="revanced_sb_new_segment_edit_by_hand_content">Желаете ли да редактирате времената за начало или край на частта?</string>
|
||||
<string name="revanced_sb_new_segment_edit_by_hand_parse_error">Зададено е невалидно време</string>
|
||||
<string name="revanced_sb_stats">Статистика</string>
|
||||
<!-- Shown in the settings preferences, and translations can be any text length. -->
|
||||
<string name="revanced_sb_stats_connection_failure">Статистиката е враменно недостъпна (API не работи)</string>
|
||||
<string name="revanced_sb_stats_loading">Зареждане...</string>
|
||||
<string name="revanced_sb_stats_sb_disabled">SponsorBlock е изключено</string>
|
||||
<string name="revanced_sb_stats_username">Вашето потреб. име: <b>%s</b></string>
|
||||
<string name="revanced_sb_stats_username_change">Докоснете за промяна потребителското име</string>
|
||||
<string name="revanced_sb_stats_username_change_unknown_error">Не може да се промени потреб. име: Състояние: %1$d%2$s</string>
|
||||
<string name="revanced_sb_stats_username_changed">Потребителското име е успешно променено</string>
|
||||
<string name="revanced_sb_stats_reputation">Репутацията ви е <b>%.2f</b></string>
|
||||
<string name="revanced_sb_stats_submissions">Създадохте <b>%s</b> части</string>
|
||||
<string name="revanced_sb_stats_saved_zero">SponsorBlock класация</string>
|
||||
<string name="revanced_sb_stats_saved">Спасихте хората от <b>%s</b> части</string>
|
||||
<string name="revanced_sb_stats_saved_sum_zero">Докоснете за да видите статистиката и тези допринесли най-много</string>
|
||||
<string name="revanced_sb_stats_saved_sum">Това е <b>%s</b> от живота им.<br>Щракнете, за да видите класацията</string>
|
||||
<string name="revanced_sb_stats_self_saved">Пропуснали сте <b>%s</b> части</string>
|
||||
<string name="revanced_sb_stats_self_saved_sum">Това е <b>%s</b></string>
|
||||
<string name="revanced_sb_stats_self_saved_reset_title">Нулиране на брояча на пропуснати части?</string>
|
||||
<string name="revanced_sb_stats_saved_hour_format">%1$s часове %2$s минути</string>
|
||||
<string name="revanced_sb_stats_saved_minute_format">%1$s минути %2$s секунди</string>
|
||||
<string name="revanced_sb_stats_saved_second_format">%s секунди</string>
|
||||
<string name="revanced_sb_color_dot_label">Цвят:</string>
|
||||
<string name="revanced_sb_color_changed">Цветът е променен</string>
|
||||
<string name="revanced_sb_color_reset">Възстанови цвета</string>
|
||||
<string name="revanced_sb_color_invalid">Невалидна стойност за цвета</string>
|
||||
<string name="revanced_sb_reset_color">Възстановяване на цвят</string>
|
||||
<string name="revanced_sb_reset">Нулиране</string>
|
||||
<string name="revanced_sb_about">Относно</string>
|
||||
<string name="revanced_sb_about_api_sum">Данните са предоставени от SponsorBlock API. Докоснете тук за повече информация и изтеглияния</string>
|
||||
</patch>
|
||||
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
|
||||
<string name="revanced_spoof_app_version_title">Подлъгване за версията на приложението</string>
|
||||
<string name="revanced_spoof_app_version_summary_on">Подправена версия</string>
|
||||
<string name="revanced_spoof_app_version_summary_off">Не подправена версия</string>
|
||||
<string name="revanced_spoof_app_version_user_dialog_message">Версията на приложението YouTube ще бъде променена на по-стара.\n\nТова ще промени външния вид и функциите на приложението.\n\nно ако по-късно се деактивира, се препоръчва да изчистите данните на приложението, за да избегнете грешки в потребителския интерфейс.</string>
|
||||
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
|
||||
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
|
||||
<string name="revanced_spoof_app_version_target_title">Подлъгване за версията на</string>
|
||||
<!-- 'RYD' is 'Return YouTube Dislike' -->
|
||||
<string name="revanced_spoof_app_version_target_entry_1">18.33.40 - Възстановете RYD в режим „инкогнито“ на Shorts</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_2">18.20.39 - Възстановяване на видео скорост & в менюто за качество</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.33.42 - Възстановява стария изглед</string>
|
||||
</patch>
|
||||
<patch id="layout.startpage.ChangeStartPagePatch">
|
||||
<string name="revanced_start_page_title">Задай начална страница</string>
|
||||
<string name="revanced_start_page_entry_0">По подразбиране</string>
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<string name="revanced_start_page_entry_1">Начало</string>
|
||||
<string name="revanced_start_page_entry_2">Търсене</string>
|
||||
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
|
||||
<string name="revanced_start_page_entry_3">Абонаменти</string>
|
||||
<string name="revanced_start_page_entry_4">Разгледайте</string>
|
||||
<string name="revanced_start_page_entry_5">Shorts</string>
|
||||
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
|
||||
<string name="revanced_start_page_entry_6">Раздел \"Вие\"</string>
|
||||
<string name="revanced_start_page_entry_7">Харесани видеа</string>
|
||||
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
|
||||
<string name="revanced_start_page_entry_8">История</string>
|
||||
<string name="revanced_start_page_entry_9">Популярни</string>
|
||||
</patch>
|
||||
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
|
||||
<string name="revanced_disable_resuming_shorts_player_title">Скриване на Shorts плейъра при стартиране</string>
|
||||
<string name="revanced_disable_resuming_shorts_player_summary_on">Shorts плейъра при стартиране на приложението е скрит</string>
|
||||
<string name="revanced_disable_resuming_shorts_player_summary_off">Shorts плейъра при стартиране на приложението се показва</string>
|
||||
</patch>
|
||||
<patch id="layout.tablet.EnableTabletLayoutPatch">
|
||||
<string name="revanced_tablet_layout_title">Включи режим за таблет</string>
|
||||
<string name="revanced_tablet_layout_summary_on">Режим за таблет е вкл.</string>
|
||||
<string name="revanced_tablet_layout_summary_off">Режим за таблет е изкл.</string>
|
||||
<string name="revanced_tablet_layout_user_dialog_message">Публикациите в общността не се показват на оформления за таблет</string>
|
||||
</patch>
|
||||
<patch id="layout.miniplayer.MiniplayerPatch">
|
||||
<string name="revanced_miniplayer_screen_title">Минимизиран екран за възпроизвеждане</string>
|
||||
<string name="revanced_miniplayer_screen_summary">Променете стила на минимизирания екран за възпроизвеждане</string>
|
||||
<string name="revanced_miniplayer_type_title">Минимизиран тип екран за гледане</string>
|
||||
<string name="revanced_miniplayer_type_entry_1">Оригинал</string>
|
||||
<string name="revanced_miniplayer_type_entry_2">Телефон</string>
|
||||
<string name="revanced_miniplayer_type_entry_3">Таблет</string>
|
||||
<string name="revanced_miniplayer_type_entry_4">Модерен 1</string>
|
||||
<string name="revanced_miniplayer_type_entry_5">Модерен 2</string>
|
||||
<string name="revanced_miniplayer_type_entry_6">Модерен 3</string>
|
||||
<string name="revanced_miniplayer_hide_expand_close_title">Бутони за разширяване и свиване на екрана</string>
|
||||
<string name="revanced_miniplayer_hide_expand_close_summary_on">Скрит.\n(плъзнете минимизирания екран на плейъра, за да разширите или затворите видеоклипа)</string>
|
||||
<string name="revanced_miniplayer_hide_expand_close_summary_off">Бутони за разширяване и свиване на екрана са видими</string>
|
||||
<string name="revanced_miniplayer_hide_subtext_title">Екранни текстове, етикети</string>
|
||||
<string name="revanced_miniplayer_hide_subtext_summary_on">Скрити</string>
|
||||
<string name="revanced_miniplayer_hide_subtext_summary_off">Показват се</string>
|
||||
<string name="revanced_miniplayer_hide_rewind_forward_title">Бутони за напред и назад</string>
|
||||
<string name="revanced_miniplayer_hide_rewind_forward_summary_on">Бутони за напред и назад са скрити</string>
|
||||
<string name="revanced_miniplayer_hide_rewind_forward_summary_off">Бутони за напред и назад са показани</string>
|
||||
<string name="revanced_miniplayer_opacity_title">Прозрачност на менютата</string>
|
||||
<string name="revanced_miniplayer_opacity_summary">Стойност на прозрачност между 0-100, където 0 е прозрачно</string>
|
||||
<string name="revanced_miniplayer_opacity_invalid_toast">Прозрачността на менюто трябва да бъде между 0-100</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeBytecodePatch">
|
||||
<string name="revanced_gradient_loading_screen_title">Фон на екрана при зареждане на видео</string>
|
||||
<string name="revanced_gradient_loading_screen_summary_on">Екранът за зареждане ще има градиентен фон</string>
|
||||
<string name="revanced_gradient_loading_screen_summary_off">Екранът за зареждане ще има плътен фон</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeResourcePatch">
|
||||
<string name="revanced_seekbar_custom_color_title">Промяна на цвета на индикатора за време</string>
|
||||
<string name="revanced_seekbar_custom_color_summary_on">Показва се персонализиран цвят на лентата за напредък</string>
|
||||
<string name="revanced_seekbar_custom_color_summary_off">Показва се оригиналния цвят на лентата за напредък</string>
|
||||
<string name="revanced_seekbar_custom_color_value_title">Персонализиран цвят на лентата за напредък</string>
|
||||
<string name="revanced_seekbar_custom_color_value_summary">Цветове на лентата за напредък</string>
|
||||
<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. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">Раздел Начало</string>
|
||||
<!-- 'Subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
<string name="revanced_alt_thumbnail_subscription_title">Раздел Абонаменти</string>
|
||||
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
|
||||
<string name="revanced_alt_thumbnail_library_title">Раздел \"Вие\"</string>
|
||||
<string name="revanced_alt_thumbnail_player_title">Плейлисти, предложения</string>
|
||||
<string name="revanced_alt_thumbnail_search_title">Резултати от търсенето</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_1">Оригинални миниатюри</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow & оригинални миниатюри</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow & Неподвижни кадри</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_4">Неподвижни кадри</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_about_summary">DeArrow предоставя миниатюри на публиката за видеоклипове. Тези миниатюри често са по-подходящи от тези, предоставени от самия YouTube. Ако е активирано, URL адресите на видео ще бъдат изпратени до API сървъра, без да се изпращат други данни. Ако видеоклипът няма миниатюри на DeArrow, ще се покажат или неговите оригинални миниатюри, или заснети кадри. Щракнете, за да научите повече за DeArrow</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_title">Показване на известие, ако API не е наличен</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_on">Показва се известие, ако DeArrow не е наличен</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_connection_toast_summary_off">Показва се известие, ако DeArrow не е наличен</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_api_url_title">Крайна точка на API на DeArrow</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_api_url_summary">URL адресът на крайната точка за съхранение на миниатюри DeArrow</string>
|
||||
<string name="revanced_alt_thumbnail_stills_about_title">Неподвижни миниатюри</string>
|
||||
<string name="revanced_alt_thumbnail_stills_about_summary">Неподвижните снимки се правят от началото / средата / края на всеки видеоклип. Тези изображения са вградени в YouTube и не се използва външен API</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_title">Използване на бързо заснемане на кадри</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_summary_on">Използват се кадри със средно качество. Миниатюрите ще се зареждат по-бързо, но видеоклипове на живо, неиздадени или много стари може да показват празни миниатюри</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_summary_off">Използване на висококачествени снимки</string>
|
||||
<string name="revanced_alt_thumbnail_stills_time_title">Времето на видеоклипа, от който ще бъдат взети кадрите</string>
|
||||
<string name="revanced_alt_thumbnail_stills_time_entry_1">Начало на видеото</string>
|
||||
<string name="revanced_alt_thumbnail_stills_time_entry_2">Средата на видеото</string>
|
||||
<string name="revanced_alt_thumbnail_stills_time_entry_3">Края на видеото</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_alt_thumbnail_dearrow_error">DeArrow временно не е наличен. (код на състоянието: %s)</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_error_generic">DeArrow временно не е наличен</string>
|
||||
</patch>
|
||||
<patch id="misc.announcements.AnnouncementsPatch">
|
||||
<string name="revanced_announcements_title">Показване на ReVanced съобщения</string>
|
||||
<string name="revanced_announcements_summary_on">Съобщенията се показват при стартиране</string>
|
||||
<string name="revanced_announcements_summary_off">Съобщенията не се показват при стартиране</string>
|
||||
<string name="revanced_announcements_enabled_summary">Показване на съобщения при стартиране</string>
|
||||
<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">Историята ви на гледане не се запазва.<br><br>Това най-вероятно е причинено от DNS блокиращ реклами или мрежов прокси.<br><br>За да коригирате това, поставете <b>s.youtube в белия списък.com</b> или изключете всички 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>
|
||||
<string name="revanced_auto_repeat_summary_off">Изключено автоматично повтаряне на текущия видеоклип</string>
|
||||
</patch>
|
||||
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
|
||||
<string name="revanced_spoof_device_dimensions_title">Лъжливи параметри на устройството</string>
|
||||
<string name="revanced_spoof_device_dimensions_summary_on">Подправената резолюция на устройството\n\nМоже да се отключи по-високо качество на видеото, но може да изпитате засичане при възпроизвеждане на видео, по-лош живот на батерията и неизвестни странични ефекти</string>
|
||||
<string name="revanced_spoof_device_dimensions_summary_off">Резолюцията на устройството не е подправена\n\nАктивирането на това не може да отключи по-високо качество на видеото</string>
|
||||
<string name="revanced_spoof_device_dimensions_user_dialog_message">Разрешаването на това може да причини прекъсване на възпроизвеждането на видео, влошен живот на батерията и неизвестни странични ефекти.</string>
|
||||
</patch>
|
||||
<patch id="misc.gms.GmsCoreSupportResourcePatch">
|
||||
<string name="microg_settings_title">GmsCore Настройки</string>
|
||||
<string name="microg_settings_summary">Настройки на GmsCore</string>
|
||||
</patch>
|
||||
<patch id="misc.links.BypassURLRedirectsPatch">
|
||||
<string name="revanced_bypass_url_redirects_title">Заобикаляне на URL пренасочване</string>
|
||||
<string name="revanced_bypass_url_redirects_summary_on">URL пренасочванията се заобикалят</string>
|
||||
<string name="revanced_bypass_url_redirects_summary_off">URL пренасочванията не се заобикалят</string>
|
||||
</patch>
|
||||
<patch id="misc.links.OpenLinksExternallyPatch">
|
||||
<string name="revanced_external_browser_title">Отваряне на връзки в браузъра</string>
|
||||
<string name="revanced_external_browser_summary_on">Отваряне на външни връзки</string>
|
||||
<string name="revanced_external_browser_summary_off">Отваряне на връзки в приложението</string>
|
||||
</patch>
|
||||
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
|
||||
<string name="revanced_remove_tracking_query_parameter_title">Премахнете параметъра на заявката за проследяване</string>
|
||||
<string name="revanced_remove_tracking_query_parameter_summary_on">Параметърът на заявката за проследяване е премахнат от връзките</string>
|
||||
<string name="revanced_remove_tracking_query_parameter_summary_off">Параметърът на заявката за проследяване не е премахнат от връзките</string>
|
||||
</patch>
|
||||
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
|
||||
<string name="revanced_disable_zoom_haptics_title">Деактивиране на вибрация при мащабиране</string>
|
||||
<string name="revanced_disable_zoom_haptics_summary_on">Вибрациите са деактивирани</string>
|
||||
<string name="revanced_disable_zoom_haptics_summary_off">Вибрациите са активирани</string>
|
||||
</patch>
|
||||
<patch id="video.quality.RememberVideoQualityPatch">
|
||||
<string name="revanced_video_quality_default_entry_1">Автоматично качество</string>
|
||||
<string name="revanced_remember_video_quality_last_selected_title">Запомни промените в качеството на видеото</string>
|
||||
<string name="revanced_remember_video_quality_last_selected_summary_on">Промените в качеството се отнасят за всички видеоклипове</string>
|
||||
<string name="revanced_remember_video_quality_last_selected_summary_off">Промените в качеството се отнасят само за текущия видеоклип</string>
|
||||
<string name="revanced_video_quality_default_wifi_title">Предпочитано качество при Wi-Fi</string>
|
||||
<string name="revanced_video_quality_default_mobile_title">Предпочитано качество при мобилни данни</string>
|
||||
<string name="revanced_remember_video_quality_mobile">мобилни данни</string>
|
||||
<string name="revanced_remember_video_quality_wifi">wi-fi</string>
|
||||
<string name="revanced_remember_video_quality_toast">Променено стандартно %1$s качество на: %2$s</string>
|
||||
</patch>
|
||||
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
|
||||
<string name="revanced_playback_speed_dialog_button_title">Показване бутон за скорост</string>
|
||||
<string name="revanced_playback_speed_dialog_button_summary_on">Бутонът е показан</string>
|
||||
<string name="revanced_playback_speed_dialog_button_summary_off">Бутонът не е показан</string>
|
||||
</patch>
|
||||
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
|
||||
<string name="revanced_custom_playback_speeds_title">Персонализирани скорости на възпроизвеждане</string>
|
||||
<string name="revanced_custom_playback_speeds_summary">Добавете или променете наличните скорости на възпроизвеждане</string>
|
||||
<string name="revanced_custom_playback_speeds_invalid">Персоналната скорост трябва да е по-малка от %s. Използване на стойности по подразбиране.</string>
|
||||
<string name="revanced_custom_playback_speeds_parse_exception">Невалидни персонализирани скорости на възпроизвеждане. Използване на стойности по подразбиране.</string>
|
||||
</patch>
|
||||
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
|
||||
<string name="revanced_remember_playback_speed_last_selected_title">Запомни промените в скоростта на възпроизвеждане</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_summary_on">Промените в скоростта на възпроизвеждане се отнасят за всички видеоклипове</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_summary_off">Промените в скоростта на възпроизвеждане се отнасят само за текущия видеоклип</string>
|
||||
<string name="revanced_playback_speed_default_title">Скорост на възпроизвеждане по подразбиране</string>
|
||||
<string name="revanced_remember_playback_speed_toast">Скоростта по подразбиране е променена на: %s</string>
|
||||
</patch>
|
||||
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
|
||||
<string name="revanced_restore_old_video_quality_menu_title">Възстановете старото меню за качество на видеото</string>
|
||||
<string name="revanced_restore_old_video_quality_menu_summary_on">Показва се старото меню за видео качество</string>
|
||||
<string name="revanced_restore_old_video_quality_menu_summary_off">Старото меню за видео качество е скрито</string>
|
||||
</patch>
|
||||
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
|
||||
<string name="revanced_slide_to_seek_title">Активиране на слайд за превъртане</string>
|
||||
<string name="revanced_slide_to_seek_summary_on">Слайд за превъртане е активиран</string>
|
||||
<string name="revanced_slide_to_seek_summary_off">Слайд за превъртане е деактивиран</string>
|
||||
</patch>
|
||||
<patch id="misc.fix.playback.SpoofClientPatch">
|
||||
<string name="revanced_spoof_client_screen_title">Подмяна на версията (на клиента)</string>
|
||||
<string name="revanced_spoof_client_screen_summary">Подмяна на версията, за да предотвратите проблеми с възпроизвеждането на видео</string>
|
||||
<string name="revanced_spoof_client_title">Подмяна на версията (на клиента)</string>
|
||||
<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_about_android_vr_summary">• Няма HDR видео\n• Детските видеоклипове не се възпроизвеждат\n• Поставените на пауза видеоклипове могат произволно да се възобновят\n• Нискокачествени миниатюри на лентата за търсене на Shorts\n• Бутон за действие за изтегляне е скрито\n• Картите на крайния екран са скрити</string>
|
||||
</patch>
|
||||
<!-- This patch is no longer used, these strings are not in use, and these strings will be deleted in the future. -->
|
||||
<patch id="misc.fix.playback.SpoofSignaturePatch">
|
||||
@@ -511,22 +1134,53 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</app>
|
||||
<app id="twitch">
|
||||
<patch id="ad.audio.AudioAdsPatch">
|
||||
<string name="revanced_block_audio_ads_title">Аудио реклами</string>
|
||||
<string name="revanced_block_audio_ads_summary_on">Аудио рекламата е блокирана</string>
|
||||
<string name="revanced_block_audio_ads_summary_off">Аудио рекламата е разблокирана</string>
|
||||
</patch>
|
||||
<patch id="ad.embedded.EmbeddedAdsPatch">
|
||||
<string name="revanced_embedded_ads_service_unavailable">%s е недостъпен. Може да се показват реклами. Опитайте друга услуга за блокиране на реклами.</string>
|
||||
<string name="revanced_embedded_ads_service_failed">%s сървърът върна грешка. Може да се показват реклами. Опитайте да превключите друга услуга за блокиране на реклами.</string>
|
||||
<string name="revanced_block_embedded_ads_title">Блокиране на вградени видеореклами</string>
|
||||
<string name="revanced_block_embedded_ads_entry_1">Деактивирано</string>
|
||||
<string name="revanced_block_embedded_ads_entry_2">Luminous прокси</string>
|
||||
<string name="revanced_block_embedded_ads_entry_3">PurpleAdBlock прокси</string>
|
||||
</patch>
|
||||
<patch id="ad.video.VideoAdsPatch">
|
||||
<string name="revanced_block_video_ads_title">Видео реклами</string>
|
||||
<string name="revanced_block_video_ads_summary_on">Видео рекламата е блокирана</string>
|
||||
<string name="revanced_block_video_ads_summary_off">Видео рекламата е разблокирана</string>
|
||||
</patch>
|
||||
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
|
||||
<string name="revanced_deleted_msg">съобщението е изтрито</string>
|
||||
<string name="revanced_show_deleted_messages_title">Покажи изтритите съобщения</string>
|
||||
<string name="revanced_show_deleted_messages_entry_1">Не показвай изтритите съобщения</string>
|
||||
<string name="revanced_show_deleted_messages_entry_2">Скрийте изтритите съобщения зад спойлер</string>
|
||||
<string name="revanced_show_deleted_messages_entry_3">Показване на изтритите съобщения като зачеркнат текст</string>
|
||||
</patch>
|
||||
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
|
||||
<string name="revanced_auto_claim_channel_points_title">Автоматично изискване на Channel Points</string>
|
||||
<string name="revanced_auto_claim_channel_points_summary_on">Автоматично изискване на Channel Points</string>
|
||||
<string name="revanced_auto_claim_channel_points_summary_off">Channel Points в канала не се изискват автоматично</string>
|
||||
</patch>
|
||||
<patch id="debug.DebugModePatch">
|
||||
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
|
||||
<string name="revanced_twitch_debug_mode_title">Активирайте режима за отстраняване на грешки в Twitch</string>
|
||||
<string name="revanced_twitch_debug_mode_summary_on">Режимът за отстраняване на грешки в Twitch е активиран (не се препоръчва)</string>
|
||||
<string name="revanced_twitch_debug_mode_summary_off">Режимът за отстраняване на грешки в Twitch е деактивиран</string>
|
||||
</patch>
|
||||
<patch id="misc.settings.SettingsPatch">
|
||||
<string name="revanced_settings">Настройки на ReVanced</string>
|
||||
<string name="revanced_ads_screen_title">Реклами</string>
|
||||
<string name="revanced_ads_screen_summary">Настройки за блокиране на реклами</string>
|
||||
<string name="revanced_chat_screen_title">Чатове</string>
|
||||
<string name="revanced_chat_screen_summary">Настройки на чата</string>
|
||||
<string name="revanced_misc_screen_title">Разни</string>
|
||||
<string name="revanced_misc_screen_summary">Допълнителни настройки</string>
|
||||
<string name="revanced_general_category_title">Основни настройки</string>
|
||||
<string name="revanced_other_category_title">Други настройки</string>
|
||||
<string name="revanced_client_ads_category_title">Клиентска реклама</string>
|
||||
<string name="revanced_surestream_ads_category_title">Сърварна реклама</string>
|
||||
<string name="revanced_twitch_debug_title">Дневник на отстраняването на грешки</string>
|
||||
<string name="revanced_twitch_debug_summary_on">Дневникът за остраняване на грешки е активиран</string>
|
||||
<string name="revanced_twitch_debug_summary_off">Дневникът за остраняване на грешки е деактивиран</string>
|
||||
|
||||
@@ -201,6 +201,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>
|
||||
@@ -792,17 +793,12 @@ 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">নতুন স্পন্সরব্লক সেগমেন্ট</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_mark_time_as_question">একটি নতুন সেগমেন্টের শুরু বা শেষ হিসাবে %1$02d:%2$02d:%3$03d সেট করবেন?</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>
|
||||
@@ -850,10 +846,10 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_spoof_app_version_target_title">স্পুফ অ্যাপ সংস্করণ লক্ষ্য</string>
|
||||
<!-- 'RYD' is 'Return YouTube Dislike' -->
|
||||
<string name="revanced_spoof_app_version_target_entry_1">18.33.40 - ছদ্মবেশি মোডে RYD পুনরুদ্ধার করে</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_2">১৮.২০.৩৯ - প্রশ্বস্ত ভিডিও স্পিড এবং গুণমান মেনু পুনরুদ্ধার করে</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_3">১৮.০৯.৩৯ - লাইব্রেরি ট্যাপ পুনরুদ্ধার করে</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_4">১৭.৪১.৩৯ - পুরোনো প্লেলিস্ট শেলফ পুনরুদ্ধার করে</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_5">১৭.৩৩.৪২ - পুরোনো UI লেআউট পুনরুদ্ধার করে</string>
|
||||
<string name="revanced_spoof_app_version_target_entry_2">18.20.39 - প্রশ্বস্ত ভিডিও স্পিড এবং গুণমান মেনু পুনরুদ্ধার করে</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.33.42 - পুরোনো UI লেআউট পুনরুদ্ধার করে</string>
|
||||
</patch>
|
||||
<patch id="layout.startpage.ChangeStartPagePatch">
|
||||
<string name="revanced_start_page_title">শুরুর পৃষ্ঠা সেট করুন</string>
|
||||
@@ -919,6 +915,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_seekbar_custom_color_value_summary">সিকবারের রং</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">সিকবারে ভুল রং দেয়া হয়েছে। মূল রং ব্যবহার করছে।</string>
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">হোম ট্যাব</string>
|
||||
@@ -959,6 +957,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>
|
||||
@@ -1040,9 +1042,6 @@ 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_use_ios_summary_on">ক্লায়েন্ট এখন iOS এ স্পুফ করা হয়েছে\n\nপার্শ্বপ্রতিক্রিয়া রয়েছে:\n• কোন এইচিডিআর ভিডিও নেই\n• ভিডিও ইতিহাস কাজ নাও করতে পারে\n• উচ্চ ভিডিও গুণমান অনুপস্থিত থাকতে পারে\n•শুধুমাত্র অডিওতে লাইভ স্ট্রিম চলবে না\n• অ্যান্ড্রয়েট ৮ সংস্করণে লাইভ স্ট্রিম উপলভ্য নয়</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_off">ক্লায়েন্টকে বর্তমানে Android VR-এর সাথে প্রতারণা করা হয়েছে\n\nসাইড এফেক্টগুলির মধ্যে রয়েছে:\n• কোনও 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>
|
||||
|
||||
@@ -171,10 +171,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. -->
|
||||
<!-- 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">
|
||||
@@ -198,6 +194,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeResourcePatch">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<!-- 'Subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
@@ -206,6 +204,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">
|
||||
|
||||
@@ -175,10 +175,6 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_sb_appearance_category">Aparença</string>
|
||||
<!-- 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. -->
|
||||
<!-- 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. -->
|
||||
<string name="revanced_sb_stats_loading">S\'està carregant...</string>
|
||||
<string name="revanced_sb_reset">Restablir</string>
|
||||
@@ -206,6 +202,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeResourcePatch">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<!-- 'Subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
|
||||
@@ -214,6 +212,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
</patch>
|
||||
<patch id="misc.announcements.AnnouncementsPatch">
|
||||
</patch>
|
||||
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
|
||||
<string name="revanced_check_watch_history_domain_name_dialog_title">Advertència</string>
|
||||
</patch>
|
||||
<patch id="misc.autorepeat.AutoRepeatPatch">
|
||||
</patch>
|
||||
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
|
||||
|
||||
@@ -214,6 +214,9 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_info_cards_section_title">Skrýt sekci informačních karet</string>
|
||||
<string name="revanced_hide_info_cards_section_summary_on">Sekce Info karty je skrytá</string>
|
||||
<string name="revanced_hide_info_cards_section_summary_off">Je zobrazena sekce Info karty</string>
|
||||
<string name="revanced_hide_key_concepts_section_title">Skrýt sekci \'Klíčové koncepty\'</string>
|
||||
<string name="revanced_hide_key_concepts_section_summary_on">Sekce \'Klíčové pojmy\' je skryta</string>
|
||||
<string name="revanced_hide_key_concepts_section_summary_off">Zobrazí se sekce \'Klíčové pojmy\'</string>
|
||||
<string name="revanced_hide_transcript_section_title">Skrýt sekci přepisu</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Přepsat oddíl je skrytý</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Je zobrazena sekce přepisu</string>
|
||||
@@ -249,7 +252,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_hide_keyword_toast_invalid_common">Neplatné klíčové slovo. Nelze použít: \'%s\' jako filtr</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">Neplatné klíčové slovo. \'%1$s\' je menší než %2$d znaků</string>
|
||||
<string name="revanced_hide_keyword_toast_invalid_broad">Klíčové slovo \'$s\' skryje všechna videa</string>
|
||||
<string name="revanced_hide_keyword_toast_invalid_broad">Klíčové slovo \'%s\' skryje všechna videa</string>
|
||||
</patch>
|
||||
<patch id="ad.general.HideAdsResourcePatch">
|
||||
<string name="revanced_hide_general_ads_title">Skrýt obecné reklamy</string>
|
||||
@@ -774,6 +777,7 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_sb_general_skipcount_sum_off">Přeskočit počet sledování není povoleno</string>
|
||||
<string name="revanced_sb_general_min_duration">Minimální doba trvání segmentu</string>
|
||||
<string name="revanced_sb_general_min_duration_sum">Segmenty kratší než tato hodnota (v sekundách) nebudou zobrazeny nebo přeskočeny</string>
|
||||
<string name="revanced_sb_general_min_duration_invalid">Neplatná doba trvání</string>
|
||||
<string name="revanced_sb_general_uuid">Vaše soukromé ID uživatele</string>
|
||||
<string name="revanced_sb_general_uuid_sum">Toto by mělo být ponecháno v soukromí. To je jako heslo a nemělo by být s nikým sdíleno. Pokud to někdo má, mohou vás zosobnit</string>
|
||||
<string name="revanced_sb_general_uuid_invalid">Soukromé ID uživatele musí mít alespoň 30 znaků</string>
|
||||
@@ -867,17 +871,13 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_sb_new_segment_choose_category">Vyberte kategorii segmentu</string>
|
||||
<string name="revanced_sb_new_segment_disabled_category">Kategorie je v nastavení zakázána. Povolte odeslat kategorii.</string>
|
||||
<string name="revanced_sb_new_segment_title">Nový segment SponsorBlock</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_mark_time_as_question">Nastavit %1$02d:%2$02d:%3$03d jako začátek nebo konec nového segmentu?</string>
|
||||
<string name="revanced_sb_new_segment_mark_time_as_question">Nastavit %s jako začátek nebo konec nového segmentu?</string>
|
||||
<string name="revanced_sb_new_segment_mark_start">Začít</string>
|
||||
<string name="revanced_sb_new_segment_mark_end">konec</string>
|
||||
<string name="revanced_sb_new_segment_now">nyní</string>
|
||||
<string name="revanced_sb_new_segment_time_start">Čas začátku segmentu</string>
|
||||
<string name="revanced_sb_new_segment_time_end">Čas ukončení segmentu v</string>
|
||||
<string name="revanced_sb_new_segment_confirm_title">Mají časy pravdu?</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">Segment je od\n\n%1$s\ndo\n%2$s\n\n(%3$s)\n\nPřipraveno k odeslání?</string>
|
||||
<string name="revanced_sb_new_segment_start_is_before_end">Začátek musí být před koncem</string>
|
||||
<string name="revanced_sb_new_segment_mark_locations_first">Nejdříve označte dvě místa v časové liště</string>
|
||||
@@ -994,6 +994,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_seekbar_custom_color_value_summary">Barva vyhledávacího panelu</string>
|
||||
<string name="revanced_seekbar_custom_color_invalid">Neplatná hodnota barvy vyhledávacího panelu. Použít výchozí hodnotu.</string>
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.BypassImageRegionRestrictions">
|
||||
<string name="revanced_bypass_image_region_restrictions_title">Obejít omezení oblasti obrázku</string>
|
||||
<string name="revanced_bypass_image_region_restrictions_summary_on">Použití hostitele obrázků yt4.gggpht.com</string>
|
||||
<string name="revanced_bypass_image_region_restrictions_summary_off">Použití originálního hostitele obrázků\n\nPovolení tohoto nastavení může opravit chybějící obrázky, které jsou blokovány v některých regionech</string>
|
||||
</patch>
|
||||
<patch id="layout.thumbnails.AlternativeThumbnailsPatch">
|
||||
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
|
||||
<string name="revanced_alt_thumbnail_home_title">Záložka Domů</string>
|
||||
@@ -1034,6 +1039,11 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_announcements_connection_failed">Připojení k poskytovateli oznámení se nezdařilo</string>
|
||||
<string name="revanced_announcements_dialog_dismiss">Zrušit</string>
|
||||
</patch>
|
||||
<patch id="misc.dns.CheckWatchHistoryDomainNameResolutionPatch">
|
||||
<string name="revanced_check_watch_history_domain_name_dialog_title">Varování</string>
|
||||
<string name="revanced_check_watch_history_domain_name_dialog_message">Vaše historie sledování není ukládána.<br><br>Příčinou je s největší pravděpodobností DNS blokátor reklam nebo síťový proxy server.<br><br>Chcete-li to opravit, přidejte<b>s.youtube.com</b> na whitelist nebo vypněte všechny DNS blokátory a proxy servery.</string>
|
||||
<string name="revanced_check_watch_history_domain_name_dialog_ignore">Znovu nezobrazovat</string>
|
||||
</patch>
|
||||
<patch id="misc.autorepeat.AutoRepeatPatch">
|
||||
<string name="revanced_auto_repeat_title">Povolit automatické opakování</string>
|
||||
<string name="revanced_auto_repeat_summary_on">Automaticky opakovat je povoleno</string>
|
||||
@@ -1115,9 +1125,15 @@ This is because Crowdin requires temporarily flattening this file and removing t
|
||||
<string name="revanced_spoof_client_summary_on">Klient je falešný</string>
|
||||
<string name="revanced_spoof_client_summary_off">Klient není spoofed\n\nPřehrávání videa nemusí fungovat</string>
|
||||
<string name="revanced_spoof_client_user_dialog_message">Vypnutí tohoto nastavení může způsobit problémy při přehrávání videa.</string>
|
||||
<string name="revanced_spoof_client_use_ios_title">Spořič do iOS</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_on">Klient je v současné době spokojen s iOS\n\nBoční efekty zahrnují:\n• No HDR video\n• Historie sledování nemusí fungovat\n• Vyšší vlastnosti videa mohou chybět\n• Živé streamy nemohou přehrát pouze\n• Živé streamy nejsou k dispozici na Android 8.0</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_off">Klient je v současné době spout s Androidem VR\n\nBoční efekty zahrnují:\n• No HDR video\n• Dětská videa nepřehrávají\n• Pozastavená videa mohou náhodně pokračovat\n• Nízká kvalita krátkých náhledů ve vyhledávacím panelu\n• Tlačítko stahování akce je vždy skryté\n• Karty s ukončenou obrazovkou jsou vždy skryté</string>
|
||||
<string name="revanced_spoof_client_type_title">Typ klienta</string>
|
||||
<string name="revanced_spoof_client_ios_force_avc_title">Vynutit iOS AVC (H.264)</string>
|
||||
<string name="revanced_spoof_client_ios_force_avc_summary_on">iOS video kodek je AVC</string>
|
||||
<string name="revanced_spoof_client_ios_force_avc_summary_off">iOS video kodek je AVC, VP9 nebo AV1</string>
|
||||
<string name="revanced_spoof_client_ios_force_avc_user_dialog_message">Povolení této funkce může zlepšit životnost baterie a opravit stahování přehrávání.\n\nAVC má maximální rozlišení 1080p a video přehrávání bude používat více dat než VP9 nebo AV1.</string>
|
||||
<string name="revanced_spoof_client_about_android_ios_title">Boční efekty iOS</string>
|
||||
<string name="revanced_spoof_client_about_android_ios_summary">• HDR je podporováno pouze s AV1 kodekem\n• Historie sledování nefunguje s obchodním účtem</string>
|
||||
<string name="revanced_spoof_client_about_android_vr_title">Boční efekty Android VR</string>
|
||||
<string name="revanced_spoof_client_about_android_vr_summary">• Žádné HDR video\n• Dětská videa nepřehrávají\n• Pozastavená videa mohou náhodně obnovit\n• Nízká kvalita rychlých náhledů ve vyhledávacím panelu\n• Tlačítko stahování je skryté\n• Karty na konci obrazovky jsou skryté</string>
|
||||
<string name="revanced_spoof_client_storyboard_timeout">Náhledy klientů nejsou k dispozici (vypršel časový limit API)</string>
|
||||
<string name="revanced_spoof_client_storyboard_io_exception">Spouštění náhledů klientů dočasně není k dispozici: %s</string>
|
||||
</patch>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user