Compare commits

..

50 Commits

Author SHA1 Message Date
semantic-release-bot
fb4256f17c chore(release): 4.12.0-dev.7 [skip ci]
# [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 ([98f9bba](98f9bba7ed))
2024-07-24 18:03:03 +00:00
oSumAtrIX
98f9bba7ed fix(SoundCloud - Enable offline sync): Stop crashing by reversing order of patching instructions from last to first to retain indices 2024-07-24 20:00:35 +02:00
semantic-release-bot
8e72067dcb chore(release): 4.12.0-dev.6 [skip ci]
# [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 ([d87f36e](d87f36e7e2))
2024-07-20 16:08:40 +00:00
oSumAtrIX
d87f36e7e2 feat: Add Spoof build info patch 2024-07-20 18:06:27 +02:00
oSumAtrIX
4432fe65df build: Bump dependencies 2024-07-20 06:14:35 +02:00
semantic-release-bot
8b0d8ee9f4 chore(release): 4.12.0-dev.5 [skip ci]
# [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)) ([250cc7c](250cc7cbde))
* **Google Photos:** Add `GmsCore support` patch ([#3414](https://github.com/ReVanced/revanced-patches/issues/3414)) ([1af65de](1af65de1f6))
2024-07-20 04:02:23 +00:00
epireyn
250cc7cbde feat: Add Hide mock location patch (#3417)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-20 06:00:19 +02:00
xob0t
1af65de1f6 feat(Google Photos): Add GmsCore support patch (#3414)
Co-authored-by: benjy3gg <benjy3gg@gmail.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-20 05:58:47 +02:00
semantic-release-bot
6e87e3044c chore(release): 4.12.0-dev.4 [skip ci]
# [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)) ([273af26](273af26274))
2024-07-20 02:57:11 +00:00
benjy3gg
273af26274 feat(Google News): Add Enable CustomTabs and GmsCore support patch (#3111)
Co-authored-by: benjy3gg <benjy3gg@gmail.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-20 04:55:08 +02:00
semantic-release-bot
2b1b081051 chore(release): 4.12.0-dev.3 [skip ci]
# [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)) ([f2bf2da](f2bf2da9a5))
2024-07-18 23:52:11 +00:00
Tim
f2bf2da9a5 fix(Instagram - Hide ads): Restore compatibility with latest version by fixing fingerprint (#3455) 2024-07-19 01:50:03 +02:00
ReVanced Bot
15317003b1 chore: Sync translations (#3451) 2024-07-18 17:22:23 +04:00
semantic-release-bot
6c81a5b65f chore(release): 4.12.0-dev.2 [skip ci]
# [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)) ([9ef51ab](9ef51abde7))
2024-07-15 19:01:14 +00:00
LisoUseInAIKyrios
9ef51abde7 feat(YouTube): Add Bypass image region restrictions patch (#3442)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-15 02:56:12 +04:00
semantic-release-bot
1d31565d47 chore(release): 4.12.0-dev.1 [skip ci]
# [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)) ([b944fb7](b944fb7bf1))
2024-07-13 23:45:56 +00:00
LightCat
b944fb7bf1 feat(SoundCloud): Add Enable offline sync patch (#3407)
Co-authored-by: bewzusore <bewzusore>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: BenCat07 <BenCat07@gitlab.com>
2024-07-14 01:43:48 +02:00
semantic-release-bot
dfd46d8e8f chore(release): 4.11.1-dev.1 [skip ci]
## [4.11.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.11.0...v4.11.1-dev.1) (2024-07-12)

### Bug Fixes

* **YouTube - Hide keyword content:** Do not hide flyout menu ([cfbc4aa](cfbc4aa6b2))
2024-07-12 22:45:58 +00:00
oSumAtrIX
f64e03a1f6 ci: Correct usage of repository variable 2024-07-13 00:43:59 +02:00
semantic-release-bot
a65970bdc2 chore(release): 4.11.1-dev.1 [skip ci]
## [4.11.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.11.0...v4.11.1-dev.1) (2024-07-12)

### Bug Fixes

* **YouTube - Hide keyword content:** Do not hide flyout menu ([cfbc4aa](cfbc4aa6b2))
2024-07-12 18:17:37 +00:00
LisoUseInAIKyrios
cfbc4aa6b2 fix(YouTube - Hide keyword content): Do not hide flyout menu 2024-07-12 22:15:13 +04:00
semantic-release-bot
b04652890e chore(release): 4.11.0 [skip ci]
# [4.11.0](https://github.com/ReVanced/revanced-patches/compare/v4.10.0...v4.11.0) (2024-07-11)

### Bug Fixes

* **Boost for reddit - Fix missing audio in video downloads:** Replace correct strings ([#3379](https://github.com/ReVanced/revanced-patches/issues/3379)) ([0b098a2](0b098a2027))
* **Windy - Unlock pro:** Revert changing package name ([#3402](https://github.com/ReVanced/revanced-patches/issues/3402)) ([dd6a9f9](dd6a9f977f))
* **Windy - Unlock pro:** Use correct package name ([#3397](https://github.com/ReVanced/revanced-patches/issues/3397)) ([e4ae9cc](e4ae9ccd26))
* **YouTube - Hide layout components:** Detect if a keyword filter hides all videos ([#3365](https://github.com/ReVanced/revanced-patches/issues/3365)) ([03eb9c0](03eb9c032a))
* **YouTube - Settings:** Move some settings to different menus, adjust default setting values ([#3415](https://github.com/ReVanced/revanced-patches/issues/3415)) ([def1ec4](def1ec4de6))
* **YouTube - SponsorBlock:** Skip segments when casting ([#3331](https://github.com/ReVanced/revanced-patches/issues/3331)) ([a81a6bf](a81a6bf5b2))

### Features

* Add `Remove share targets` patch ([#3334](https://github.com/ReVanced/revanced-patches/issues/3334)) ([70e54f8](70e54f8794))
* Add translations ([#2963](https://github.com/ReVanced/revanced-patches/issues/2963)) ([f5f0240](f5f024024a))
* **Bandcamp:** Add `Remove play limits` patch ([#3366](https://github.com/ReVanced/revanced-patches/issues/3366)) ([f0fb2fa](f0fb2fa3ba))
* **Instagram:** Add `Hide ads` patch ([#3380](https://github.com/ReVanced/revanced-patches/issues/3380)) ([decdff9](decdff9037))
* **RAR:** Add `Hide purchase reminder` patch ([#3321](https://github.com/ReVanced/revanced-patches/issues/3321)) ([55556f3](55556f3efc))
* **Soundcloud:** Add `Hide ads` and `Disable telemetry` patch ([#3386](https://github.com/ReVanced/revanced-patches/issues/3386)) ([a036c1f](a036c1fa0a))
* **Stocard:** Add `Hide offers tab` and `Hide story bubbles` patch ([#3359](https://github.com/ReVanced/revanced-patches/issues/3359)) ([e2f9193](e2f9193aa8))
2024-07-11 18:56:56 +00:00
LisoUseInAIKyrios
4fe1dbe9e0 chore: Merge branch dev to main (#3369) 2024-07-11 22:54:46 +04:00
ReVanced Bot
32acfbaee7 chore: Sync translations (#3427) 2024-07-11 02:24:16 +04:00
semantic-release-bot
d02a490f36 chore(release): 4.11.0-dev.7 [skip ci]
# [4.11.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.6...v4.11.0-dev.7) (2024-07-10)

### Features

* **Bandcamp:** Add `Remove play limits` patch ([#3366](https://github.com/ReVanced/revanced-patches/issues/3366)) ([f0fb2fa](f0fb2fa3ba))
2024-07-10 22:23:36 +00:00
xob0t
f0fb2fa3ba feat(Bandcamp): Add Remove play limits patch (#3366)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-11 00:21:40 +02:00
semantic-release-bot
4885d4ef00 chore(release): 4.11.0-dev.6 [skip ci]
# [4.11.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.5...v4.11.0-dev.6) (2024-07-10)

### Bug Fixes

* **YouTube - SponsorBlock:** Skip segments when casting ([#3331](https://github.com/ReVanced/revanced-patches/issues/3331)) ([a81a6bf](a81a6bf5b2))

### Features

* **Soundcloud:** Add `Hide ads` and `Disable telemetry` patch ([#3386](https://github.com/ReVanced/revanced-patches/issues/3386)) ([a036c1f](a036c1fa0a))
2024-07-10 22:15:51 +00:00
patchink0
a036c1fa0a feat(Soundcloud): Add Hide ads and Disable telemetry patch (#3386)
Co-authored-by: bewzusore <bewzusore>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-11 00:13:44 +02:00
Sami Alaoui
a81a6bf5b2 fix(YouTube - SponsorBlock): Skip segments when casting (#3331)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-07-11 00:12:03 +02:00
semantic-release-bot
81836119c0 chore(release): 4.11.0-dev.5 [skip ci]
# [4.11.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.4...v4.11.0-dev.5) (2024-07-05)

### Bug Fixes

* **YouTube - Settings:** Move some settings to different menus, adjust default setting values ([#3415](https://github.com/ReVanced/revanced-patches/issues/3415)) ([def1ec4](def1ec4de6))
2024-07-05 17:40:57 +00:00
LisoUseInAIKyrios
def1ec4de6 fix(YouTube - Settings): Move some settings to different menus, adjust default setting values (#3415) 2024-07-05 21:38:52 +04:00
ReVanced Bot
72f02c8d2f chore: Sync translations (#3400) 2024-07-04 02:05:06 +04:00
semantic-release-bot
5e0dd932cd chore(release): 4.11.0-dev.4 [skip ci]
# [4.11.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.3...v4.11.0-dev.4) (2024-07-01)

### Bug Fixes

* **Windy - Unlock pro:** Revert changing package name ([#3402](https://github.com/ReVanced/revanced-patches/issues/3402)) ([dd6a9f9](dd6a9f977f))
2024-07-01 13:02:34 +00:00
oSumAtrIX
dd6a9f977f fix(Windy - Unlock pro): Revert changing package name (#3402) 2024-07-01 15:00:34 +02:00
semantic-release-bot
7d4c2e820c chore(release): 4.11.0-dev.3 [skip ci]
# [4.11.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.2...v4.11.0-dev.3) (2024-06-30)

### Bug Fixes

* **Windy - Unlock pro:** Use correct package name ([#3397](https://github.com/ReVanced/revanced-patches/issues/3397)) ([e4ae9cc](e4ae9ccd26))
2024-06-30 17:49:56 +00:00
Benedikt Strasser
e4ae9ccd26 fix(Windy - Unlock pro): Use correct package name (#3397) 2024-06-30 19:47:51 +02:00
oSumAtrIX
d469604f0f chore: Add contribution guidelines for translations 2024-06-30 16:16:43 +03:00
semantic-release-bot
1fa7dc83a7 chore(release): 4.11.0-dev.2 [skip ci]
# [4.11.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.1...v4.11.0-dev.2) (2024-06-27)

### Features

* Add translations ([#2963](https://github.com/ReVanced/revanced-patches/issues/2963)) ([f5f0240](f5f024024a))
2024-06-27 20:53:19 +00:00
ReVanced Bot
f5f024024a feat: Add translations (#2963)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2024-06-27 22:51:13 +02:00
oSumAtrIX
c5f0bc41e2 ci: Use correct push path to trigger pushing strings 2024-06-27 22:47:44 +02:00
semantic-release-bot
a80825cbc2 chore(release): 4.11.0-dev.1 [skip ci]
# [4.11.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.10.1-dev.2...v4.11.0-dev.1) (2024-06-27)

### Features

* Add `Remove share targets` patch ([#3334](https://github.com/ReVanced/revanced-patches/issues/3334)) ([70e54f8](70e54f8794))
* **Instagram:** Add `Hide ads` patch ([#3380](https://github.com/ReVanced/revanced-patches/issues/3380)) ([decdff9](decdff9037))
* **RAR:** Add `Hide purchase reminder` patch ([#3321](https://github.com/ReVanced/revanced-patches/issues/3321)) ([55556f3](55556f3efc))
* **Stocard:** Add `Hide offers tab` and `Hide story bubbles` patch ([#3359](https://github.com/ReVanced/revanced-patches/issues/3359)) ([e2f9193](e2f9193aa8))
2024-06-27 20:30:10 +00:00
Twin
55556f3efc feat(RAR): Add Hide purchase reminder patch (#3321)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-06-27 22:27:59 +02:00
1fexd
70e54f8794 feat: Add Remove share targets patch (#3334)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-06-27 22:27:29 +02:00
epireyn
e2f9193aa8 feat(Stocard): Add Hide offers tab and Hide story bubbles patch (#3359)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-06-27 22:26:35 +02:00
Tim
decdff9037 feat(Instagram): Add Hide ads patch (#3380)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-06-27 22:25:43 +02:00
LisoUseInAIKyrios
8f6519d206 chore: attempt to fix crowdin push 2024-06-27 21:48:46 +03:00
LisoUseInAIKyrios
b0b809d222 chore: Simplify string for localization 2024-06-25 17:06:32 +03:00
semantic-release-bot
979af7ddd0 chore(release): 4.10.1-dev.2 [skip ci]
## [4.10.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.10.1-dev.1...v4.10.1-dev.2) (2024-06-24)

### Bug Fixes

* **Boost for reddit - Fix missing audio in video downloads:** Replace correct strings ([#3379](https://github.com/ReVanced/revanced-patches/issues/3379)) ([0b098a2](0b098a2027))
2024-06-24 17:10:03 +00:00
Yan
0b098a2027 fix(Boost for reddit - Fix missing audio in video downloads): Replace correct strings (#3379) 2024-06-24 19:07:55 +02:00
LisoUseInAIKyrios
2bfd75ce96 chore(YouTube - Spoof client): Update side effects disclaimer 2024-06-24 17:56:16 +03:00
162 changed files with 55566 additions and 1754 deletions

View File

@@ -20,11 +20,11 @@ jobs:
- name: Open pull request
uses: repo-sync/pull-request@v2
with:
destination_branch: 'main'
pr_title: 'chore: ${{ env.MESSAGE }}'
destination_branch: "main"
pr_title: "chore: ${{ env.MESSAGE }}"
pr_body: |
This pull request will ${{ env.MESSAGE }}.
## Dependencies before merge
- [ ] https://github.com/revanced/revanced-integrations

View File

@@ -1,34 +1,35 @@
name: Pull strings
on:
workflow_dispatch:
schedule:
- cron: 0 0 1 * *
workflow_dispatch:
schedule:
- cron: 0 0 1 * *
jobs:
pull:
name: Pull strings
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
pull:
name: Pull strings
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: dev
- name: Pull strings
uses: crowdin/github-action@v1
with:
config: crowdin.yml
download_translations: true
localization_branch_name: feat/translations
create_pull_request: true
pull_request_title: "chore: Sync translations"
pull_request_body: "Sync translations from [crowdin.com/project/revanced](https://crowdin.com/project/revanced)"
pull_request_base_branch_name: "dev"
commit_message: "chore: Sync translations"
github_user_name: revanced-bot
github_user_email: github@revanced.app
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
- name: Pull strings
uses: crowdin/github-action@v2
with:
config: crowdin.yml
download_translations: true
localization_branch_name: feat/translations
create_pull_request: true
pull_request_title: "chore: Sync translations"
pull_request_body: "Sync translations from [crowdin.com/project/revanced](https://crowdin.com/project/revanced)"
pull_request_base_branch_name: "dev"
commit_message: "chore: Sync translations"
github_user_name: revanced-bot
github_user_email: github@revanced.app
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View File

@@ -1,27 +1,29 @@
name: Push strings
on:
workflow_dispatch:
push:
paths:
- /src/main/resources/addresources/values/strings.xml
workflow_dispatch:
push:
branches:
- dev
paths:
- src/main/resources/addresources/values/strings.xml
jobs:
push:
name: Push strings
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
push:
name: Push strings
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Push strings
uses: crowdin/github-action@v1
with:
config: crowdin.yml
upload_sources: true
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
- name: Push strings
uses: crowdin/github-action@v2
with:
config: crowdin.yml
upload_sources: true
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

View File

@@ -42,7 +42,7 @@ jobs:
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
fingerprint: ${{ env.GPG_FINGERPRINT }}
fingerprint: ${{ vars.GPG_FINGERPRINT }}
- name: Release
env:

View File

@@ -1,3 +1,154 @@
# [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)
### Bug Fixes
* **YouTube - Hide keyword content:** Do not hide flyout menu ([687c9f7](https://github.com/ReVanced/revanced-patches/commit/687c9f7eb03cca5f7b3486f07f2e3453ebc77faf))
## [4.11.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.11.0...v4.11.1-dev.1) (2024-07-12)
### Bug Fixes
* **YouTube - Hide keyword content:** Do not hide flyout menu ([687c9f7](https://github.com/ReVanced/revanced-patches/commit/687c9f7eb03cca5f7b3486f07f2e3453ebc77faf))
# [4.11.0](https://github.com/ReVanced/revanced-patches/compare/v4.10.0...v4.11.0) (2024-07-11)
### Bug Fixes
* **Boost for reddit - Fix missing audio in video downloads:** Replace correct strings ([#3379](https://github.com/ReVanced/revanced-patches/issues/3379)) ([b43db98](https://github.com/ReVanced/revanced-patches/commit/b43db98e8483e2939d8fb9cd02443f24aeaae3c3))
* **Windy - Unlock pro:** Revert changing package name ([#3402](https://github.com/ReVanced/revanced-patches/issues/3402)) ([541f1e7](https://github.com/ReVanced/revanced-patches/commit/541f1e702665630a3737f67a4cc0c4f7b4899f8f))
* **Windy - Unlock pro:** Use correct package name ([#3397](https://github.com/ReVanced/revanced-patches/issues/3397)) ([1d8459a](https://github.com/ReVanced/revanced-patches/commit/1d8459ac992b12371c41df3c25b6386119770d15))
* **YouTube - Hide layout components:** Detect if a keyword filter hides all videos ([#3365](https://github.com/ReVanced/revanced-patches/issues/3365)) ([6aa47ec](https://github.com/ReVanced/revanced-patches/commit/6aa47ec1050cf32158ab608441c0649501184971))
* **YouTube - Settings:** Move some settings to different menus, adjust default setting values ([#3415](https://github.com/ReVanced/revanced-patches/issues/3415)) ([7201ac4](https://github.com/ReVanced/revanced-patches/commit/7201ac45c158682413c8584aac7bb37b770fc924))
* **YouTube - SponsorBlock:** Skip segments when casting ([#3331](https://github.com/ReVanced/revanced-patches/issues/3331)) ([d9395fd](https://github.com/ReVanced/revanced-patches/commit/d9395fdbca45cf68fbc63469e228eefbd6c2bf2e))
### Features
* Add `Remove share targets` patch ([#3334](https://github.com/ReVanced/revanced-patches/issues/3334)) ([9414122](https://github.com/ReVanced/revanced-patches/commit/94141228163aee8d051491db51fc1e4c8b86f0e6))
* Add translations ([#2963](https://github.com/ReVanced/revanced-patches/issues/2963)) ([69ea6f3](https://github.com/ReVanced/revanced-patches/commit/69ea6f3bc2b5f419320f17c150489dcb9eed76ce))
* **Bandcamp:** Add `Remove play limits` patch ([#3366](https://github.com/ReVanced/revanced-patches/issues/3366)) ([ad8d3bb](https://github.com/ReVanced/revanced-patches/commit/ad8d3bb1c86f1324234e890f1171ec4a18e56dd9))
* **Instagram:** Add `Hide ads` patch ([#3380](https://github.com/ReVanced/revanced-patches/issues/3380)) ([c6b2f8c](https://github.com/ReVanced/revanced-patches/commit/c6b2f8c0172b4fd142927d9448ed855831c86ae4))
* **RAR:** Add `Hide purchase reminder` patch ([#3321](https://github.com/ReVanced/revanced-patches/issues/3321)) ([8fbe7e3](https://github.com/ReVanced/revanced-patches/commit/8fbe7e3d38c43adfa0755bcbe87f8c6b7696da3a))
* **Soundcloud:** Add `Hide ads` and `Disable telemetry` patch ([#3386](https://github.com/ReVanced/revanced-patches/issues/3386)) ([3c79f3d](https://github.com/ReVanced/revanced-patches/commit/3c79f3d34d978aead60de19e64d05fbebc1bc73a))
* **Stocard:** Add `Hide offers tab` and `Hide story bubbles` patch ([#3359](https://github.com/ReVanced/revanced-patches/issues/3359)) ([fbd0507](https://github.com/ReVanced/revanced-patches/commit/fbd0507ce5cdeb93a1f661aa8097139c61e643a0))
# [4.11.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.6...v4.11.0-dev.7) (2024-07-10)
### Features
* **Bandcamp:** Add `Remove play limits` patch ([#3366](https://github.com/ReVanced/revanced-patches/issues/3366)) ([ad8d3bb](https://github.com/ReVanced/revanced-patches/commit/ad8d3bb1c86f1324234e890f1171ec4a18e56dd9))
# [4.11.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.5...v4.11.0-dev.6) (2024-07-10)
### Bug Fixes
* **YouTube - SponsorBlock:** Skip segments when casting ([#3331](https://github.com/ReVanced/revanced-patches/issues/3331)) ([d9395fd](https://github.com/ReVanced/revanced-patches/commit/d9395fdbca45cf68fbc63469e228eefbd6c2bf2e))
### Features
* **Soundcloud:** Add `Hide ads` and `Disable telemetry` patch ([#3386](https://github.com/ReVanced/revanced-patches/issues/3386)) ([3c79f3d](https://github.com/ReVanced/revanced-patches/commit/3c79f3d34d978aead60de19e64d05fbebc1bc73a))
# [4.11.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.4...v4.11.0-dev.5) (2024-07-05)
### Bug Fixes
* **YouTube - Settings:** Move some settings to different menus, adjust default setting values ([#3415](https://github.com/ReVanced/revanced-patches/issues/3415)) ([7201ac4](https://github.com/ReVanced/revanced-patches/commit/7201ac45c158682413c8584aac7bb37b770fc924))
# [4.11.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.3...v4.11.0-dev.4) (2024-07-01)
### Bug Fixes
* **Windy - Unlock pro:** Revert changing package name ([#3402](https://github.com/ReVanced/revanced-patches/issues/3402)) ([541f1e7](https://github.com/ReVanced/revanced-patches/commit/541f1e702665630a3737f67a4cc0c4f7b4899f8f))
# [4.11.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.2...v4.11.0-dev.3) (2024-06-30)
### Bug Fixes
* **Windy - Unlock pro:** Use correct package name ([#3397](https://github.com/ReVanced/revanced-patches/issues/3397)) ([1d8459a](https://github.com/ReVanced/revanced-patches/commit/1d8459ac992b12371c41df3c25b6386119770d15))
# [4.11.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.11.0-dev.1...v4.11.0-dev.2) (2024-06-27)
### Features
* Add translations ([#2963](https://github.com/ReVanced/revanced-patches/issues/2963)) ([69ea6f3](https://github.com/ReVanced/revanced-patches/commit/69ea6f3bc2b5f419320f17c150489dcb9eed76ce))
# [4.11.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.10.1-dev.2...v4.11.0-dev.1) (2024-06-27)
### Features
* Add `Remove share targets` patch ([#3334](https://github.com/ReVanced/revanced-patches/issues/3334)) ([9414122](https://github.com/ReVanced/revanced-patches/commit/94141228163aee8d051491db51fc1e4c8b86f0e6))
* **Instagram:** Add `Hide ads` patch ([#3380](https://github.com/ReVanced/revanced-patches/issues/3380)) ([c6b2f8c](https://github.com/ReVanced/revanced-patches/commit/c6b2f8c0172b4fd142927d9448ed855831c86ae4))
* **RAR:** Add `Hide purchase reminder` patch ([#3321](https://github.com/ReVanced/revanced-patches/issues/3321)) ([8fbe7e3](https://github.com/ReVanced/revanced-patches/commit/8fbe7e3d38c43adfa0755bcbe87f8c6b7696da3a))
* **Stocard:** Add `Hide offers tab` and `Hide story bubbles` patch ([#3359](https://github.com/ReVanced/revanced-patches/issues/3359)) ([fbd0507](https://github.com/ReVanced/revanced-patches/commit/fbd0507ce5cdeb93a1f661aa8097139c61e643a0))
## [4.10.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.10.1-dev.1...v4.10.1-dev.2) (2024-06-24)
### Bug Fixes
* **Boost for reddit - Fix missing audio in video downloads:** Replace correct strings ([#3379](https://github.com/ReVanced/revanced-patches/issues/3379)) ([b43db98](https://github.com/ReVanced/revanced-patches/commit/b43db98e8483e2939d8fb9cd02443f24aeaae3c3))
## [4.10.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.10.0...v4.10.1-dev.1) (2024-06-23)

View File

@@ -83,6 +83,10 @@ Features can be requested by opening an issue using the
If you encounter a bug while using ReVanced Patches, open an issue using the
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
## 🌐 Submitting translations
You can contribute translations at [translate.revanced.app](https://translate.revanced.app).
## 🧑‍⚖️ Guidelines for requesting or contributing patches
To maintain a high-quality and ethical collection of patches, the following guidelines for requesting
@@ -107,7 +111,6 @@ are unaffected by this change.
* Payment circumvention: We do not accept patches that exist solely to bypass payment for the app or any of its features
* Malicious patches: Patches that are malicious in nature are not allowed
## 📝 How to contribute
1. Before contributing, it is recommended to open an issue to discuss your change
@@ -120,6 +123,6 @@ described in the [ReVanced Patcher documentation](https://github.com/ReVanced/re
that your pull request closes in the description of your pull request
5. Our team will review your pull request and provide feedback. Once your pull request is approved,
it will be merged into the `dev` branch and will be included in the next release of ReVanced Patches
❤️ Thank you for considering contributing to ReVanced Patches,
ReVanced

View File

@@ -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
@@ -155,6 +199,12 @@ public final class app/revanced/patches/all/screenshot/removerestriction/RemoveS
public static fun values ()[Lapp/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch$MethodCall;
}
public final class app/revanced/patches/all/shortcut/sharetargets/RemoveShareTargetsPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/all/shortcut/sharetargets/RemoveShareTargetsPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
}
public final class app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
public static final field INSTANCE Lapp/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch;
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;
@@ -175,6 +225,12 @@ public final class app/revanced/patches/backdrops/misc/pro/ProUnlockPatch : app/
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/bandcamp/limitations/RemovePlayLimitsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/bandcamp/limitations/RemovePlayLimitsPatch;
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/candylinkvpn/UnlockProPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/candylinkvpn/UnlockProPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -205,6 +261,36 @@ 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/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
@@ -241,6 +327,12 @@ public final class app/revanced/patches/inshorts/ad/HideAdsPatch : app/revanced/
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/instagram/patches/ad/HideAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/instagram/patches/ad/HideAdsPatch;
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/instagram/patches/ads/timeline/HideTimelineAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/instagram/patches/ads/timeline/HideTimelineAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -523,6 +615,16 @@ public final class app/revanced/patches/pixiv/ads/HideAdsPatch : app/revanced/pa
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/rar/misc/annoyances/purchasereminder/HidePurchaseReminderPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/rar/misc/annoyances/purchasereminder/HidePurchaseReminderPatch;
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/rar/misc/annoyances/purchasereminder/fingerprints/ShowReminderFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint {
public static final field INSTANCE Lapp/revanced/patches/rar/misc/annoyances/purchasereminder/fingerprints/ShowReminderFingerprint;
}
public final class app/revanced/patches/reddit/ad/banner/HideBannerPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/ad/banner/HideBannerPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
@@ -1010,6 +1112,24 @@ public final class app/revanced/patches/songpal/badge/RemoveNotificationBadgePat
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/soundcloud/ad/HideAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/soundcloud/ad/HideAdsPatch;
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/soundcloud/analytics/DisableTelemetryPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/soundcloud/analytics/DisableTelemetryPatch;
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/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
@@ -1034,6 +1154,18 @@ public final class app/revanced/patches/spotify/navbar/PremiumNavbarTabResourceP
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
}
public final class app/revanced/patches/stocard/layout/HideOffersTabPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/stocard/layout/HideOffersTabPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
}
public final class app/revanced/patches/stocard/layout/HideStoryBubblesPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/stocard/layout/HideStoryBubblesPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
}
public final class app/revanced/patches/strava/subscription/UnlockSubscriptionPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/strava/subscription/UnlockSubscriptionPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -1666,6 +1798,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
@@ -1732,6 +1870,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;
}
@@ -1959,7 +2107,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

View File

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

View File

@@ -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]

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}
}

View File

@@ -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")
}

View File

@@ -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;"
}
}

View File

@@ -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."
)
}

View File

@@ -13,7 +13,6 @@ import app.revanced.util.resource.BaseResource
import app.revanced.util.resource.StringResource
import org.w3c.dom.Node
import java.io.Closeable
import java.util.*
/**
* An identifier of an app. For example, `youtube`.
@@ -55,6 +54,95 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
*/
private lateinit var resources: Map<Value, Resources>
/**
* Map of Crowdin locales to Android resource locale names.
*
* Fixme: Instead this patch should detect what locale regions are present in both patches and the target app,
* and automatically merge into the appropriate existing target file.
* So if a target app has only 'es', then the Crowdin file of 'es-rES' should merge into that.
* But if a target app has specific regions (such as 'pt-rBR'),
* then the Crowdin region specific file should merged into that.
*/
private val locales = mapOf(
"af-rZA" to "af",
"am-rET" to "am",
"ar-rSA" to "ar",
"as-rIN" to "as",
"az-rAZ" to "az",
"be-rBY" to "be",
"bg-rBG" to "bg",
"bn-rBD" to "bn",
"bs-rBA" to "bs",
"ca-rES" to "ca",
"cs-rCZ" to "cs",
"da-rDK" to "da",
"de-rDE" to "de",
"el-rGR" to "el",
"es-rES" to "es",
"et-rEE" to "et",
"eu-rES" to "eu",
"fa-rIR" to "fa",
"fi-rFI" to "fi",
"tl-rPH" to "tl",
"fr-rFR" to "fr",
"gl-rES" to "gl",
"gu-rIN" to "gu",
"hi-rIN" to "hi",
"hr-rHR" to "hr",
"hu-rHU" to "hu",
"hy-rAM" to "hy",
"in-rID" to "in",
"is-rIS" to "is",
"it-rIT" to "it",
"iw-rIL" to "iw",
"ja-rJP" to "ja",
"ka-rGE" to "ka",
"kk-rKZ" to "kk",
"km-rKH" to "km",
"kn-rIN" to "kn",
"ko-rKR" to "ko",
"ky-rKG" to "ky",
"lo-rLA" to "lo",
"lt-rLT" to "lt",
"lv-rLV" to "lv",
"mk-rMK" to "mk",
"ml-rIN" to "ml",
"mn-rMN" to "mn",
"mr-rIN" to "mr",
"ms-rMY" to "ms",
"my-rMM" to "my",
"nb-rNO" to "nb",
"ne-rIN" to "ne",
"nl-rNL" to "nl",
"or-rIN" to "or",
"pa-rIN" to "pa",
"pl-rPL" to "pl",
"pt-rBR" to "pt-rBR",
"pt-rPT" to "pt-rPT",
"ro-rRO" to "ro",
"ru-rRU" to "ru",
"si-rLK" to "si",
"sk-rSK" to "sk",
"sl-rSI" to "sl",
"sq-rAL" to "sq",
"sr-rSP" to "sr",
"sv-rSE" to "sv",
"sw-rKE" to "sw",
"ta-rIN" to "ta",
"te-rIN" to "te",
"th-rTH" to "th",
"tl-rPH" to "tl",
"tr-rTR" to "tr",
"uk-rUA" to "uk",
"ur-rIN" to "ur",
"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",
)
/*
The strategy of this patch is to stage resources present in `/resources/addresources`.
These resources are organized by their respective value and patch.
@@ -75,23 +163,25 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
/**
* Puts resources under `/resources/addresources/<value>/<resourceKind>.xml` into the map.
*
* @param value The value of the resource. For example, `values` or `values-de`.
* @param sourceValue The source value of the resource. For example, `values` or `values-de-rDE`.
* @param destValue The destination value of the resource. For example, 'values' or 'values-de'.
* @param resourceKind The kind of the resource. For example, `strings` or `arrays`.
* @param transform A function that transforms the [Node]s from the XML files to a [BaseResource].
*/
fun addResources(
value: Value,
sourceValue: Value,
destValue: Value = sourceValue,
resourceKind: String,
transform: (Node) -> BaseResource,
) {
inputStreamFromBundledResource(
"addresources",
"$value/$resourceKind.xml",
"$sourceValue/$resourceKind.xml",
)?.let { stream ->
// Add the resources associated with the given value to the map,
// instead of overwriting it.
// This covers the example case such as adding strings and arrays of the same value.
getOrPut(value, ::mutableMapOf).apply {
getOrPut(destValue, ::mutableMapOf).apply {
context.xmlEditor[stream].use { editor ->
val document = editor.file
@@ -121,13 +211,13 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
// Staged resources consumed by AddResourcesPatch#invoke(PatchClass)
// are later used in AddResourcesPatch#close.
try {
val addStringResources = { value: Value ->
addResources(value, "strings", StringResource::fromNode)
val addStringResources = { source: Value, dest: Value ->
addResources(source, dest, "strings", StringResource::fromNode)
}
Locale.getISOLanguages().asSequence().map { "values-$it" }.forEach { addStringResources(it) }
addStringResources("values")
locales.forEach { (source, dest) -> addStringResources("values-$source", "values-$dest") }
addStringResources("values", "values")
addResources("values", "arrays", ArrayResource::fromNode)
addResources("values", "values", "arrays", ArrayResource::fromNode)
} catch (e: Exception) {
throw PatchException("Failed to read resources", e)
}
@@ -257,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 ->

View File

@@ -0,0 +1,32 @@
package app.revanced.patches.all.shortcut.sharetargets
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.util.asSequence
import app.revanced.util.getNode
import org.w3c.dom.Element
import java.io.FileNotFoundException
import java.util.logging.Logger
@Patch(
name = "Remove share targets",
description = "Removes share targets like directly sharing to a frequent contact.",
use = false,
)
@Suppress("unused")
object RemoveShareTargetsPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
try {
context.document["res/xml/shortcuts.xml"]
} catch (_: FileNotFoundException) {
return Logger.getLogger(this::class.java.name).warning("The app has no shortcuts")
}.use { document ->
val rootNode = document.getNode("shortcuts") as? Element ?: return@use
document.getElementsByTagName("share-target").asSequence().forEach {
rootNode.removeChild(it)
}
}
}
}

View File

@@ -0,0 +1,23 @@
package app.revanced.patches.bandcamp.limitations
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.bandcamp.limitations.fingerprints.HandlePlaybackLimitsPatch
import app.revanced.util.exception
@Patch(
name = "Remove play limits",
description = "Disables purchase nagging and playback limits of not purchased tracks.",
compatiblePackages = [CompatiblePackage("com.bandcamp.android")],
)
@Suppress("unused")
object RemovePlayLimitsPatch : BytecodePatch(
setOf(HandlePlaybackLimitsPatch),
) {
override fun execute(context: BytecodeContext) =
HandlePlaybackLimitsPatch.result?.mutableMethod?.addInstructions(0, "return-void")
?: throw HandlePlaybackLimitsPatch.exception
}

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.bandcamp.limitations.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object HandlePlaybackLimitsPatch : MethodFingerprint(
strings = listOf("play limits processing track", "found play_count"),
)

View File

@@ -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")
}
}
}
}

View File

@@ -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;") },
)

View File

@@ -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"
}

View File

@@ -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
}

View File

@@ -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",
)

View File

@@ -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;")
},
)

View File

@@ -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"),
)

View File

@@ -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),
)

View File

@@ -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
}

View File

@@ -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"
}

View File

@@ -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
}

View File

@@ -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",
)

View File

@@ -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;")
},
)

View File

@@ -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),
)

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -0,0 +1,29 @@
package app.revanced.patches.instagram.patches.ad
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.instagram.patches.ad.fingerprints.AdInjectorFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide ads",
description = "Hides ads in stories, discover, profile, etc." +
"An ad can still appear once when refreshing the home feed.",
compatiblePackages = [CompatiblePackage("com.instagram.android")],
)
@Suppress("unused")
object HideAdsPatch : BytecodePatch(
setOf(AdInjectorFingerprint),
) {
override fun execute(context: BytecodeContext) =
AdInjectorFingerprint.result?.mutableMethod?.addInstructions(
0,
"""
const/4 v0, 0x0
return v0
""",
) ?: throw AdInjectorFingerprint.exception
}

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.instagram.patches.ad.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object AdInjectorFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PRIVATE.value,
parameters = listOf("L", "L"),
strings = listOf(
"SponsoredContentController.insertItem",
"SponsoredContentController::Delivery",
),
)

View File

@@ -12,7 +12,7 @@ import app.revanced.util.resultOrThrow
@Patch(
name = "Remove background playback restrictions",
description = "Removes restrictions on background playback.",
description = "Removes restrictions on background playback, including playing kids videos in the background.",
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",

View File

@@ -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,

View File

@@ -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"
)
)

View File

@@ -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"),
)

View File

@@ -0,0 +1,24 @@
package app.revanced.patches.rar.misc.annoyances.purchasereminder
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.rar.misc.annoyances.purchasereminder.fingerprints.ShowReminderFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide purchase reminder",
description = "Hides the popup that reminds you to purchase the app.",
compatiblePackages = [CompatiblePackage("com.rarlab.rar")],
)
@Suppress("unused")
object HidePurchaseReminderPatch : BytecodePatch(
setOf(ShowReminderFingerprint),
) {
override fun execute(context: BytecodeContext) {
ShowReminderFingerprint.result?.mutableMethod?.addInstruction(0, "return-void")
?: throw ShowReminderFingerprint.exception
}
}

View File

@@ -0,0 +1,13 @@
package app.revanced.patches.rar.misc.annoyances.purchasereminder.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
object ShowReminderFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("AdsNotify;") && methodDef.name == "show"
},
)

View File

@@ -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()
}

View File

@@ -25,7 +25,7 @@ object FixAudioMissingInDownloadsPatch : BytecodePatch(
)
override fun execute(context: BytecodeContext) {
DownloadAudioFingerprint.resultOrThrow().let { result ->
result.scanResult.stringsScanResult!!.matches.take(2).forEach { match ->
result.scanResult.stringsScanResult!!.matches.forEach { match ->
result.mutableMethod.apply {
val replacement = endpointReplacements[match.string]
val register = getInstruction<OneRegisterInstruction>(match.index).registerA

View File

@@ -3,5 +3,5 @@ package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads.f
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object DownloadAudioFingerprint : MethodFingerprint(
strings = setOf("/DASH_audio.mp4", "/audio", "v.redd.it", "/"),
strings = setOf("/DASH_audio.mp4", "/audio"),
)

View File

@@ -22,5 +22,5 @@ object UnlockSubscriptionPatch : BytecodePatch(
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected),
) {
override fun execute(context: BytecodeContext) =
listOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
}

View File

@@ -11,8 +11,11 @@ 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.returnEarly
@@ -42,8 +45,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,
@@ -53,7 +56,7 @@ abstract class BaseGmsCoreSupportPatch(
) : BytecodePatch(
name = "GmsCore support",
description = "Allows patched Google apps to run without root and under a different package name " +
"by using GmsCore instead of Google Play Services.",
"by using GmsCore instead of Google Play Services.",
dependencies = setOf(
ChangePackageNamePatch::class,
gmsCoreSupportResourcePatch::class,
@@ -62,6 +65,9 @@ abstract class BaseGmsCoreSupportPatch(
compatiblePackages = compatiblePackages,
fingerprints = setOf(
GmsCoreSupportFingerprint,
GooglePlayUtilityFingerprint,
ServiceCheckFingerprint,
CastDynamiteModuleFingerprint,
mainActivityOnCreateFingerprint,
) + fingerprints,
requiresIntegrations = true,
@@ -91,16 +97,19 @@ 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 + ServiceCheckFingerprint + CastDynamiteModuleFingerprint).returnEarly()
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",
"checkGmsCore(Landroid/app/Activity;)V",
) ?: throw mainActivityOnCreateFingerprint.exception
// Change the vendor of GmsCore in ReVanced Integrations.
@@ -192,7 +201,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 +314,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",

View File

@@ -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 "$packageName.android.c2dm",
"com.google.android.libraries.photos.api.mars" to "$packageName.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
)
}
)
}

View File

@@ -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

View File

@@ -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"),
)

View File

@@ -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")
)

View File

@@ -0,0 +1,72 @@
package app.revanced.patches.soundcloud.ad
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.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.ad.fingerprints.InterceptFingerprint
import app.revanced.patches.soundcloud.shared.fingerprints.FeatureConstructorFingerprint
import app.revanced.patches.soundcloud.ad.fingerprints.UserConsumerPlanConstructorFingerprint
import app.revanced.util.resultOrThrow
@Patch(
name = "Hide ads",
compatiblePackages = [CompatiblePackage("com.soundcloud.android")],
)
@Suppress("unused")
object HideAdsPatch : BytecodePatch(
setOf(FeatureConstructorFingerprint, UserConsumerPlanConstructorFingerprint, InterceptFingerprint),
) {
override fun execute(context: BytecodeContext) {
// Enable a preset feature to disable audio ads 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, "no_audio_ads"
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)),
)
}
// Overwrite the JSON response from the server to a paid plan, which hides all ads in the app.
// This does not enable paid features, as they are all checked for on the backend.
// This method is the constructor of a class representing a "UserConsumerPlan" object parsed from JSON data.
// p1 is the "currentTier" value, dictating which features to enable in the app.
// p4 is the "consumerPlanUpsells" value, a list of plans to try to sell to the user.
// p5 is the "currentConsumerPlan" value, the type of plan currently subscribed to.
// p6 is the "currentConsumerPlanTitle" value, the name of the plan currently subscribed to, shown to the user.
UserConsumerPlanConstructorFingerprint.resultOrThrow().mutableMethod.addInstructions(
0,
"""
const-string p1, "high_tier"
new-instance p4, Ljava/util/ArrayList;
invoke-direct {p4}, Ljava/util/ArrayList;-><init>()V
const-string p5, "go-plus"
const-string p6, "SoundCloud Go+"
""",
)
// Prevent verification of an HTTP header containing the user's current plan, which would contradict the previous patch.
InterceptFingerprint.resultOrThrow().let { result ->
val conditionIndex = result.scanResult.patternScanResult!!.endIndex
result.mutableMethod.addInstruction(
conditionIndex,
"return-object p1",
)
}
}
}

View File

@@ -0,0 +1,22 @@
package app.revanced.patches.soundcloud.ad.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object InterceptFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC.value,
parameters = listOf("L"),
opcodes = listOf(
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
),
strings = listOf("SC-Mob-UserPlan", "Configuration"),
customFingerprint = { _, classDef ->
classDef.sourceFile == "ApiUserPlanInterceptor.java"
},
)

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.soundcloud.ad.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object UserConsumerPlanConstructorFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Ljava/lang/String;", "Z", "Ljava/lang/String;", "Ljava/util/List;", "Ljava/lang/String;", "Ljava/lang/String;"),
customFingerprint = { _, classDef ->
classDef.sourceFile == "UserConsumerPlan.kt"
},
)

View File

@@ -0,0 +1,24 @@
package app.revanced.patches.soundcloud.analytics
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.soundcloud.analytics.fingerprints.CreateTrackingApiFingerprint
import app.revanced.util.resultOrThrow
@Patch(
name = "Disable telemetry",
description = "Disables SoundCloud's telemetry system.",
compatiblePackages = [CompatiblePackage("com.soundcloud.android")],
)
@Suppress("unused")
object DisableTelemetryPatch : BytecodePatch(
setOf(CreateTrackingApiFingerprint),
) {
override fun execute(context: BytecodeContext) =
// Empty the "backend" argument to abort the initializer.
CreateTrackingApiFingerprint.resultOrThrow()
.mutableMethod.addInstruction(0, "const-string p1, \"\"")
}

View File

@@ -0,0 +1,12 @@
package app.revanced.patches.soundcloud.analytics.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object CreateTrackingApiFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef, classDef ->
classDef.sourceFile == "DefaultTrackingApiFactory.kt" && methodDef.name == "create"
},
)

View File

@@ -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, \"\"")
}
}
}
}

View File

@@ -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"
}
)

View File

@@ -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"
}
)

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.soundcloud.shared.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object FeatureConstructorFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Ljava/lang/String;", "Z", "Ljava/util/List;"),
customFingerprint = { _, classDef ->
classDef.sourceFile == "Feature.kt"
},
)

View File

@@ -0,0 +1,27 @@
package app.revanced.patches.stocard.layout
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.util.childElementsSequence
import app.revanced.util.getNode
@Patch(
name = "Hide offers tab",
compatiblePackages = [CompatiblePackage("de.stocard.stocard")],
)
@Suppress("unused")
object HideOffersTabPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
context.document["res/menu/bottom_navigation_menu.xml"].use { document ->
document.getNode("menu").apply {
removeChild(
childElementsSequence().first {
it.attributes.getNamedItem("android:id")?.nodeValue?.contains("offer") ?: false
},
)
}
}
}
}

View File

@@ -0,0 +1,27 @@
package app.revanced.patches.stocard.layout
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.util.getNode
@Patch(
name = "Hide story bubbles",
compatiblePackages = [CompatiblePackage("de.stocard.stocard")],
)
@Suppress("unused")
object HideStoryBubblesPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
context.document["res/layout/rv_story_bubbles_list.xml"].use { document ->
document.getNode("androidx.recyclerview.widget.RecyclerView").apply {
arrayOf(
"android:layout_width",
"android:layout_height",
).forEach {
attributes.getNamedItem(it).nodeValue = "0dp"
}
}
}
}
}

View File

@@ -13,7 +13,6 @@ import app.revanced.patches.tiktok.interaction.speed.fingerprints.OnRenderFirstF
import app.revanced.patches.tiktok.interaction.speed.fingerprints.SetSpeedFingerprint
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x
import com.android.tools.smali.dexlib2.iface.reference.MethodReference

View File

@@ -102,7 +102,6 @@ object HideLayoutComponentsPatch : BytecodePatch(
),
),
SwitchPreference("revanced_hide_emergency_box"),
SwitchPreference("revanced_hide_expandable_chip"),
SwitchPreference("revanced_hide_info_panels"),
SwitchPreference("revanced_hide_join_membership_button"),
SwitchPreference("revanced_disable_like_subscribe_glow"),
@@ -143,6 +142,7 @@ object HideLayoutComponentsPatch : BytecodePatch(
)
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
SwitchPreference("revanced_hide_expandable_chip"),
SwitchPreference("revanced_hide_gray_separator"),
PreferenceScreen(
key = "revanced_custom_filter_screen",
@@ -155,10 +155,6 @@ object HideLayoutComponentsPatch : BytecodePatch(
),
)
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
SwitchPreference("revanced_hide_video_quality_menu_footer"),
)
LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME)
LithoFilterPatch.addFilter(KEYWORD_FILTER_CLASS_NAME)

View File

@@ -74,6 +74,7 @@ object HidePlayerFlyoutMenuPatch : ResourcePatch() {
SwitchPreference("revanced_hide_player_flyout_more_info"),
SwitchPreference("revanced_hide_player_flyout_audio_track"),
SwitchPreference("revanced_hide_player_flyout_watch_in_vr"),
SwitchPreference("revanced_hide_video_quality_menu_footer"),
)
)
)

View File

@@ -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)
}
}

View File

@@ -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.GENERAL_LAYOUT.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)
}
}

View File

@@ -7,12 +7,10 @@ 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.all.misc.resources.AddResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackManagerFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
@@ -29,7 +27,6 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
PlayerTypeHookPatch::class,
VideoInformationPatch::class,
SettingsPatch::class,
AddResourcesPatch::class
],
compatiblePackages = [
CompatiblePackage(
@@ -69,12 +66,6 @@ object BackgroundPlaybackPatch : BytecodePatch(
"Lapp/revanced/integrations/youtube/patches/BackgroundPlaybackPatch;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences(
NonInteractivePreference("revanced_background_playback")
)
BackgroundPlaybackManagerFingerprint.resultOrThrow().mutableMethod.addInstructions(
0,
"""

View File

@@ -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,
),
@@ -61,9 +59,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
),
),
fingerprints = setOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint,
PrimeMethodFingerprint,

View File

@@ -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")
)

View File

@@ -0,0 +1,134 @@
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.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) {
fun MethodFingerprint.alsoResolve(fingerprint: MethodFingerprint) =
also { resolve(context, fingerprint.resultOrThrow().classDef) }.resultOrThrow()
loadImageUrlMethod = MessageDigestImageUrlFingerprint
.alsoResolve(MessageDigestImageUrlParentFingerprint).mutableMethod
loadImageSuccessCallbackMethod = OnSucceededFingerprint
.alsoResolve(OnResponseStartedFingerprint).mutableMethod
loadImageErrorCallbackMethod = OnFailureFingerprint
.alsoResolve(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
""",
)
}
)
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -14,6 +14,9 @@ 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.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
@@ -24,6 +27,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.util.MethodUtil
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch(
description = "Hooks YouTube to get information about the current playing video.",
@@ -32,6 +38,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
object VideoInformationPatch : BytecodePatch(
setOf(
PlayerInitFingerprint,
MdxPlayerDirectorSetVideoStageFingerprint,
CreateVideoPlayerSeekbarFingerprint,
PlayerControllerSetTimeReferenceFingerprint,
OnPlaybackSpeedItemClickFingerprint
@@ -42,12 +49,16 @@ object VideoInformationPatch : BytecodePatch(
private lateinit var playerInitMethod: MutableMethod
private var playerInitInsertIndex = 4
private lateinit var mdxInitMethod: MutableMethod
private var mdxInitInsertIndex = -1
private var mdxInitInsertRegister = -1
private lateinit var timeMethod: MutableMethod
private var timeInitInsertIndex = 2
private lateinit var speedSelectionInsertMethod: MutableMethod
private var speedSelectionInsertIndex = 0
private var speedSelectionValueRegister = 0
private var speedSelectionInsertIndex = -1
private var speedSelectionValueRegister = -1
// Used by other patches.
internal lateinit var setPlaybackSpeedContainerClassFieldReference: String
@@ -55,44 +66,48 @@ object VideoInformationPatch : BytecodePatch(
internal lateinit var setPlaybackSpeedMethodReference: String
override fun execute(context: BytecodeContext) {
with(PlayerInitFingerprint.result!!) {
with(PlayerInitFingerprint.resultOrThrow()) {
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
// hook the player controller for use through integrations
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
// seek method
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method
val seekFingerprintResultMethod =
SeekFingerprint.also { it.resolve(context, classDef) }.resultOrThrow().method
// create helper method
val seekHelperMethod = ImmutableMethod(
seekFingerprintResultMethod.definingClass,
"seekTo",
listOf(ImmutableMethodParameter("J", null, "time")),
"Z",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null, null,
MutableMethodImplementation(4)
).toMutable()
// get enum type for the seek helper method
val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString()
// insert helper method instructions
seekHelperMethod.addInstructions(
0,
"""
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z
move-result p1
return p1
"""
)
val seekHelperMethod = generateSeekMethodHelper(seekFingerprintResultMethod)
// add the seekTo method to the class for the integrations to call
mutableClass.methods.add(seekHelperMethod)
}
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
onCreateHookMdx(INTEGRATIONS_CLASS_DESCRIPTOR, "initializeMdx")
// MDX seek method
val mdxSeekFingerprintResultMethod =
MdxSeekFingerprint.apply { resolve(context, classDef) }.resultOrThrow().method
// create helper method
val mdxSeekHelperMethod = generateSeekMethodHelper(mdxSeekFingerprintResultMethod)
// add the seekTo method to the class for the integrations to call
mutableClass.methods.add(mdxSeekHelperMethod)
}
with(CreateVideoPlayerSeekbarFingerprint.result!!) {
val videoLengthMethodResult = VideoLengthFingerprint.also { it.resolve(context, classDef) }.result!!
@@ -103,7 +118,7 @@ object VideoInformationPatch : BytecodePatch(
addInstruction(
videoLengthMethodResult.scanResult.patternScanResult!!.endIndex,
"invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
"invoke-static { v$videoLengthRegister, v$dummyRegisterForLong }, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
)
}
}
@@ -158,6 +173,35 @@ object VideoInformationPatch : BytecodePatch(
userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
}
private fun generateSeekMethodHelper(seekMethod: Method): MutableMethod {
// 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()
// get enum type for the seek helper method
val seekSourceEnumType = seekMethod.parameterTypes[1].toString()
// 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
}
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
@@ -180,6 +224,19 @@ object VideoInformationPatch : BytecodePatch(
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
)
/**
* Hook the MDX player director. Called when playing videos while casting to a big screen device.
*
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
* @param targetMethodName The name of the static method to invoke when the player controller is created.
*/
internal fun onCreateHookMdx(targetMethodClass: String, targetMethodName: String) =
mdxInitMethod.insert(
mdxInitInsertIndex++,
"v$mdxInitInsertRegister",
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
)
/**
* Hook the video time.
* The hook is usually called once per second.

View File

@@ -0,0 +1,8 @@
package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object MdxPlayerDirectorSetVideoStageFingerprint : MethodFingerprint(
strings = listOf("MdxDirector setVideoStage ad should be null when videoStage is not an Ad state ")
)

View File

@@ -0,0 +1,23 @@
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
internal object MdxSeekFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",
parameters = listOf("J", "L"),
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.RETURN,
),
customFingerprint = { methodDef, _ ->
// The instruction count is necessary here to avoid matching the relative version
// of the seek method we're after, which has the same function signature as the
// regular one, is in the same class, and even has the exact same 3 opcodes pattern.
methodDef.implementation!!.instructions.count() == 3
}
)

View File

@@ -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,41 @@ 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)
}

View File

@@ -0,0 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<!-- 'Join' should be translated using the same localized wording YouTube displays.
This appears in the video player for certain videos. -->
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
<!-- '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. -->
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
This button usually appears when searching for a YT creator. -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<!-- 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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<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">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
</patch>
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
</app>
</resources>

View File

@@ -0,0 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<!-- 'Join' should be translated using the same localized wording YouTube displays.
This appears in the video player for certain videos. -->
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
<!-- '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. -->
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
This button usually appears when searching for a YT creator. -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<!-- 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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<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">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
</patch>
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
</app>
</resources>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<!-- 'Join' should be translated using the same localized wording YouTube displays.
This appears in the video player for certain videos. -->
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
<!-- '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. -->
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
This button usually appears when searching for a YT creator. -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<!-- 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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<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">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
</patch>
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
</app>
</resources>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,537 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_confirm_user_dialog_title">Желаете ли да продължите?</string>
<string name="revanced_settings_reset">Нулиране</string>
<string name="revanced_settings_restart_title">Опреснете и рестартирайте</string>
<string name="revanced_settings_restart">Рестартиране</string>
<string name="revanced_settings_import">Импортиране</string>
<string name="revanced_settings_import_copy">Копиране</string>
<string name="revanced_settings_import_reset">Настройките на ReVanced бяха нулирани</string>
<string name="revanced_settings_import_success">Следните настройки бяха импортирани успешно: %d</string>
<string name="revanced_settings_import_failure_parse">Импортирането беше неуспешно: %s</string>
</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_dialog_open_website_text">Отвори сайта</string>
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
<string name="revanced_settings_about_links_dev_header">Забележка</string>
<string name="revanced_pref_import_export_title">Импортиране / Експортиране</string>
<string name="revanced_pref_import_export_summary">Импортиране / Експортиране на ReVanced настройките</string>
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">Относно</string>
<string name="revanced_settings_screen_01_ads_title">Реклами</string>
<string name="revanced_settings_screen_02_alt_thumbnails_title">Алтернативни миниатюри</string>
<string name="revanced_settings_screen_03_feed_title">Поток</string>
<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_08_swipe_controls_title">Контроли с плъзгане</string>
<string name="revanced_settings_screen_11_misc_title">Разни</string>
<string name="revanced_settings_screen_12_video_title">Видео</string>
</patch>
<patch id="misc.debugging.DebuggingPatch">
<string name="revanced_debug_screen_title">Отстраняване на грешки</string>
<string name="revanced_debug_screen_summary">Активиране или деактивиране на отстраняването на грешки</string>
<string name="revanced_debug_title">Дневник на отстраняването на грешки</string>
<string name="revanced_debug_summary_on">Дневникът за остраняване на грешки е активиран</string>
<string name="revanced_debug_summary_off">Дневникът за остраняване на грешки е деактивиран</string>
<string name="revanced_debug_protobuffer_title">Буфер на протокола за дневника</string>
<string name="revanced_debug_protobuffer_summary_on">Файлове с дневници за грешки включват буфера</string>
<string name="revanced_debug_protobuffer_summary_off">Файлове с дневници за грешки не включват буфера</string>
<string name="revanced_debug_stacktrace_title">Следи от стека на дневника</string>
<string name="revanced_debug_stacktrace_summary_on">Дневникът за отстраняване на грешки съдържа следи от стека</string>
<string name="revanced_debug_stacktrace_summary_off">Дневникът за отстраняване на грешки не съдържа следи от стека</string>
<string name="revanced_debug_toast_on_error_title">Покажи системно съобщение при ReVanced грешка</string>
<string name="revanced_debug_toast_on_error_summary_on">Системно съобщение ще бъде показано, ако се появи грешка</string>
<string name="revanced_debug_toast_on_error_summary_off">Системно съобщение няма да бъде показано, ако се появи грешка</string>
<string name="revanced_debug_toast_on_error_user_dialog_message">Ако изключите системните съобщения, ще скриете всички уведомления за ReVanced грешки. \n\nНяма да бъдете уведомени, ако настъпят неочаквани събития.</string>
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<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>
<!-- '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_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_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_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_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_summary_on">Бутонът е скрит</string>
<string name="revanced_hide_show_more_button_summary_off">Бутонът е показан</string>
<string name="revanced_hide_timed_reactions_title">Скриване на времевите реакции</string>
<string name="revanced_hide_timed_reactions_summary_on">Времевите реакции са скрити</string>
<string name="revanced_hide_timed_reactions_summary_off">Времевите реакции са показани</string>
<string name="revanced_hide_search_result_shelf_header_title">Скриване на заглавието на рафта с резултатите от търсенето</string>
<string name="revanced_hide_search_result_shelf_header_summary_on">Заглавието на рафта е скрито</string>
<string name="revanced_hide_search_result_shelf_header_summary_off">Заглавието е показано</string>
<string name="revanced_hide_channel_guidelines_title">Скриване на насоките на канала</string>
<string name="revanced_hide_channel_guidelines_summary_on">Насоките на канала са скрити</string>
<string name="revanced_hide_channel_guidelines_summary_off">Насоките на канала са показани</string>
<string name="revanced_hide_expandable_chip_title">Скриване на разширяемия чип под видеоклиповете</string>
<string name="revanced_hide_expandable_chip_summary_on">Разширяващите се чипове са скрити</string>
<string name="revanced_hide_expandable_chip_summary_off">Разширяващите се чипове са показани</string>
<string name="revanced_hide_video_quality_menu_footer_title">Скриване на футъра на менюто за качество на видеото</string>
<string name="revanced_hide_video_quality_menu_footer_summary_on">Футърът на менюто за качество на видеото е скрит</string>
<string name="revanced_hide_video_quality_menu_footer_summary_off">Футърът на менюто за качество на видеото е показан</string>
<string name="revanced_hide_community_posts_title">Скриване на публикациите от общността</string>
<string name="revanced_hide_community_posts_summary_on">Публикациите от общността са скрити</string>
<string name="revanced_hide_community_posts_summary_off">Публикациите от общността са показани</string>
<string name="revanced_hide_compact_banner_title">Скриване на компактните банери</string>
<string name="revanced_hide_compact_banner_summary_on">Компактните банери са скрити</string>
<string name="revanced_hide_compact_banner_summary_off">Компактните банери са показани</string>
<string name="revanced_hide_movies_section_title">Скриване на раздела за филми</string>
<string name="revanced_hide_movies_section_summary_on">Разделът за филми е скрит</string>
<string name="revanced_hide_movies_section_summary_off">Разделът за филми е показан</string>
<string name="revanced_hide_feed_survey_title">Скриване на анкетите в новинарския поток</string>
<string name="revanced_hide_feed_survey_summary_on">Aнкетите в новинарския поток са скрити</string>
<string name="revanced_hide_feed_survey_summary_off">Aнкетите в новинарския поток са показани</string>
<string name="revanced_hide_community_guidelines_title">Скриване на насоките на общността</string>
<string name="revanced_hide_community_guidelines_summary_on">Насоките на общността са скрити</string>
<string name="revanced_hide_community_guidelines_summary_off">Насоките на общността са показани</string>
<string name="revanced_hide_subscribers_community_guidelines_title">Скриване на насоките за общността на абонатите</string>
<string name="revanced_hide_subscribers_community_guidelines_summary_on">Насоките за общността на абонатите са скрити</string>
<string name="revanced_hide_subscribers_community_guidelines_summary_off">Насоките за общността на абонатите са показани</string>
<string name="revanced_hide_channel_member_shelf_title">Скриване на рафта на канала</string>
<string name="revanced_hide_channel_member_shelf_summary_on">Рафтът на канала е скрит</string>
<string name="revanced_hide_channel_member_shelf_summary_off">Рафтът на канала е показан</string>
<string name="revanced_hide_emergency_box_title">Скриване аварийните кутии</string>
<string name="revanced_hide_emergency_box_summary_on">Аварийните кутии са скрити</string>
<string name="revanced_hide_emergency_box_summary_off">Аварийните кутии са показани</string>
<string name="revanced_hide_info_panels_title">Скриване на информационните панели</string>
<string name="revanced_hide_info_panels_summary_on">Информационните панели са скрити</string>
<string name="revanced_hide_info_panels_summary_off">Информационните панели са показани</string>
<string name="revanced_hide_medical_panels_title">Скриване на медицинските панели</string>
<string name="revanced_hide_medical_panels_summary_on">Медицинските панели са скрити</string>
<string name="revanced_hide_medical_panels_summary_off">Медицинските панели са показани</string>
<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_quick_actions_title">Скриване на бързите действия в режим на цял екран</string>
<string name="revanced_hide_quick_actions_summary_on">Бързите действия в режим на цял екран са скрити</string>
<string name="revanced_hide_quick_actions_summary_off">Бързите действия в режим на цял екран са показани</string>
<string name="revanced_hide_related_videos_title">Скриване на свързаните видеоклипове в бързите действия</string>
<string name="revanced_hide_related_videos_summary_on">Свързаните видеоклипове в бързите действия са скирти</string>
<string name="revanced_hide_related_videos_summary_off">Свързаните видеоклипове в бързите действия са показани</string>
<string name="revanced_hide_image_shelf_title">Скриване на рафта с изображения в резултатите от търсенето</string>
<string name="revanced_hide_image_shelf_summary_on">Рафтът с изображения в резултатите от търсенето е скрит</string>
<string name="revanced_hide_image_shelf_summary_off">Рафтът с изображения в резултатите от търсенето е показан</string>
<string name="revanced_hide_latest_posts_ads_title">Скриване на последните публикации</string>
<string name="revanced_hide_latest_posts_ads_summary_on">Последните публикации са скрити</string>
<string name="revanced_hide_latest_posts_ads_summary_off">Последните публикации са показани</string>
<string name="revanced_hide_mix_playlists_title">Скриване на разбърканите плейлисти</string>
<string name="revanced_hide_mix_playlists_summary_on">Разбърканите плейлисти са скрити</string>
<string name="revanced_hide_mix_playlists_summary_off">Разбърканите плейлисти са показани</string>
<string name="revanced_hide_artist_cards_title">Скриване на картите на артистите</string>
<string name="revanced_hide_artist_cards_summary_on">Картите на артистите са скрити</string>
<string name="revanced_hide_artist_cards_summary_off">Картите на артистите са показани</string>
<string name="revanced_hide_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_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_transcript_section_summary_on">Разделът за транскрипция е скрит</string>
<string name="revanced_hide_transcript_section_summary_off">Разделът за транскрипция е показан</string>
<string name="revanced_hide_description_components_screen_title">Описание на видеото</string>
<string name="revanced_hide_description_components_screen_summary">Скриване или показване на компонентите за описание на видеоклиповете</string>
<string name="revanced_custom_filter_screen_title">Потребителски филтър</string>
<string name="revanced_custom_filter_screen_summary">Скриване на компоненти с помощта на потребителски филтри</string>
<string name="revanced_custom_filter_title">Активиране на потребителските филтри</string>
<string name="revanced_custom_filter_summary_on">Потребителският филтър е активиран</string>
<string name="revanced_custom_filter_summary_off">Потребителският филтър е деактивиран</string>
<string name="revanced_custom_filter_strings_title">Потребителски филтър</string>
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<string name="revanced_custom_filter_strings_summary">Списък с низове за изграждане на пътя на компонента, които да се филтрират, разделени с нов ред</string>
<string name="revanced_custom_filter_toast_invalid_syntax">Невалиден потребителски филтър: %s</string>
<string name="revanced_hide_keyword_content_screen_title">Скриване на съдържанието с ключови думи</string>
<string name="revanced_hide_keyword_content_screen_summary">Скриване на видеоклипове в резултатите от търсенуя и в новинарския поток с помощта на филтри с ключови думи</string>
<string name="revanced_hide_keyword_content_home_title">Скриване на видеоклипове на началната страница с ключови думи</string>
<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_off">Видеоклиповете в раздела за абонаменти са са филтрирани с ключови думи</string>
<string name="revanced_hide_keyword_content_search_title">Скриване на резултати от търсения с ключови думи</string>
<string name="revanced_hide_keyword_content_search_summary_on">Резултатите от търсения са филтрирани с ключови думи</string>
<string name="revanced_hide_keyword_content_search_summary_off">Резултатите от търсения не са филтрирани с ключови думи</string>
<string name="revanced_hide_keyword_content_phrases_title">Ключови думи, които да бъдат скрити</string>
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<string name="revanced_hide_keyword_content_phrases_summary">Ключови думи и фрази, които да бъдат скрити, разделени с нови редове\n\nДуми с главни букви в средата трябва да бъдат въведени с големи букви (например: iPhone, TikTok, LeBlanc)</string>
<string name="revanced_hide_keyword_content_about_title">За филтриране с ключови думи</string>
<string name="revanced_hide_keyword_content_about_summary">Начало/Абонамент/Резултатите от търсенето се филтрират, за да се скрие съдържанието, което съответства на ключовите фрази\n\nОграничения\n• Някои кратки видеоклипове може да не са скрити\n• Някои компоненти на потребителския интерфейс може да не са скрити\n• Търсенето на ключова дума може да не покаже резултати</string>
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch 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_off">Рекламите в режим на цял екран са показани</string>
<string name="revanced_hide_buttoned_ads_summary_on">Рекламите като бутон са скрити</string>
<string name="revanced_hide_buttoned_ads_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>
<string name="revanced_hide_products_banner_title">Скриване на банера за показване на продукти</string>
<string name="revanced_hide_products_banner_summary_on">Банерът е скрит</string>
<string name="revanced_hide_products_banner_summary_off">Банерът е показан</string>
<string name="revanced_hide_shopping_links_title">Скриване на връзките за пазаруване в описанието на видеоклипа</string>
<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_summary_on">Бутонът е скрит</string>
<string name="revanced_hide_visit_store_button_summary_off">Бутонът е показан</string>
<string name="revanced_hide_web_search_results_title">Скриване на резултатите от уеб търсенето</string>
<string name="revanced_hide_web_search_results_summary_on">Резултатите от уеб търсенето са скрити</string>
<string name="revanced_hide_web_search_results_summary_off">Резултатите от уеб търсенето са показани</string>
<string name="revanced_hide_merchandise_banners_title">Скриване на банерите за стоки</string>
<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. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
<string name="revanced_hide_get_premium_title">Скриване на YouTube Premium промоции</string>
<string name="revanced_hide_get_premium_summary_on">YouTube Premium промоциите под видео плейъра са скрити</string>
<string name="revanced_hide_get_premium_summary_off">YouTube Premium промоциите под видео плейъра са показани</string>
</patch>
<patch id="ad.video.VideoAdsPatch">
<string name="revanced_hide_video_ads_title">Скриване на видео рекламите</string>
<string name="revanced_hide_video_ads_summary_on">Видео рекламите са скрити</string>
<string name="revanced_hide_video_ads_summary_off">Видео рекламите са показани</string>
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
<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_off">Бутонът не е показан</string>
<string name="revanced_copy_video_url_timestamp_title">Показване на бутона за копиране на 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>
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<string name="revanced_external_downloader_screen_title">Външни изтегляния</string>
<string name="revanced_external_downloader_screen_summary">Настройки за използване на външно приложение за изтегляне</string>
<string name="revanced_external_downloader_title">Показване на бутона за изтегляне чрез външно приложение</string>
<string name="revanced_external_downloader_summary_on">Бутонът за изтегляне е показан в плейъра</string>
<string name="revanced_external_downloader_summary_off">Бутонът за изтегляне не е показан в плейъра</string>
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
<string name="revanced_external_downloader_action_button_title">Отмяна на бутона за изтегляне</string>
<string name="revanced_external_downloader_action_button_summary_on">Бутонът за изтегляне отваря избраното от Вас външно приложение за изтегляне</string>
<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>
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
<string name="revanced_disable_precise_seeking_gesture_title">Деактивиране на жеста за точно търсене</string>
<string name="revanced_disable_precise_seeking_gesture_summary_on">Жестът е деактивиран</string>
<string name="revanced_disable_precise_seeking_gesture_summary_off">Жестът е активиран</string>
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
<string name="revanced_seekbar_tapping_title">Активиране на докосването на лентата за време</string>
<string name="revanced_seekbar_tapping_summary_on">Докосването на лентата за време е включено</string>
<string name="revanced_seekbar_tapping_summary_off">Докосването на лентата за време е изключено</string>
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
<string name="revanced_swipe_brightness_title">Задаване на яркост чрез плъзгане</string>
<string name="revanced_swipe_brightness_summary_on">Задаването на яркост чрез плъзгане е включено</string>
<string name="revanced_swipe_brightness_summary_off">Задаването на яркост чрез плъзгане е изключено</string>
<string name="revanced_swipe_volume_title">Настройване на звука чрез плъзгане</string>
<string name="revanced_swipe_volume_summary_on">Настройването на звука чрез плъзгане е включено</string>
<string name="revanced_swipe_volume_summary_off">Настройването на звука чрез плъзгане е изключено</string>
<string name="revanced_swipe_press_to_engage_title">Активиране на жеста натискане за преместване</string>
<string name="revanced_swipe_press_to_engage_summary_on">Натискането при плъзгане е включено</string>
<string name="revanced_swipe_press_to_engage_summary_off">Натискането при плъзгане е изключено</string>
<string name="revanced_swipe_haptic_feedback_title">Активиране на хептичната обратна връзка</string>
<string name="revanced_swipe_haptic_feedback_summary_on">Хептичната обратна връзка е активирана</string>
<string name="revanced_swipe_haptic_feedback_summary_off">Хептичната обратна връзка е деактивирана</string>
<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_overlay_timeout_title">Задръжка на плъзгащата контрола</string>
<string name="revanced_swipe_overlay_timeout_summary">Време за което плъзгащата контрола е видима</string>
<string name="revanced_swipe_text_overlay_size_title">Размер на текста при плъзгане</string>
<string name="revanced_swipe_text_overlay_size_summary">Размера на текста на плъзгащите контроли</string>
<string name="revanced_swipe_overlay_background_alpha_title">Видимост на фона на плъзгащите контроли</string>
<string name="revanced_swipe_overlay_background_alpha_summary">Видимостта на фона на плъзгащите контроли</string>
<string name="revanced_swipe_threshold_title">Праг на величината на плъзгане</string>
<string name="revanced_swipe_threshold_summary">Праг преди да се осъществи плъзгането</string>
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
<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>
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<string name="revanced_ryd_about">Относно</string>
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<patch id="layout.sponsorblock.SponsorBlockResourcePatch">
<string name="revanced_sb_enable_sb">Включване на SponsorBlock</string>
<string name="revanced_sb_appearance_category">Облик</string>
<!-- Translations should use language similar to 'revanced_ryd_compact_layout_title' -->
<string name="revanced_sb_guidelines_preference_title">Преглед на ръководните линии</string>
<string name="revanced_sb_guidelines_popup_already_read">Вече прочетох</string>
<string name="revanced_sb_general">Общи</string>
<string name="revanced_sb_general_uuid_sum">Това трябва да се държи тайно. То е като парола и не трябва да се споделя с никого. Ако някой го има, то той може да се представи вместо вас</string>
<string name="revanced_sb_api_url_reset">Нулиране URL адреса на API</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_segments_sponsor">Спонсор</string>
<string name="revanced_sb_skip_automatically">Да се прескача от само себе си</string>
<string name="revanced_sb_skip_ignore">Изключване</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_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_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_edit_by_hand_content">Желаете ли да редактирате времената за начало или край на частта?</string>
<string name="revanced_sb_stats">Статистика</string>
<!-- Shown in the settings preferences, and translations can be any text length. -->
<string name="revanced_sb_stats_loading">Зареждане...</string>
<string name="revanced_sb_stats_sb_disabled">SponsorBlock е изключено</string>
<string name="revanced_sb_stats_username_changed">Потребителското име е успешно променено</string>
<string name="revanced_sb_color_changed">Цветът е променен</string>
<string name="revanced_sb_reset">Нулиране</string>
<string name="revanced_sb_about">Относно</string>
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<string name="revanced_start_page_entry_0">По подразбиране</string>
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<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. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
<string name="revanced_announcements_dialog_dismiss">Отхвърли</string>
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
<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">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
<string name="revanced_block_embedded_ads_entry_1">Деактивирано</string>
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_ads_screen_title">Реклами</string>
<string name="revanced_misc_screen_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>
</patch>
</app>
</resources>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
<patch id="misc.debugging.DebuggingPatch">
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<!-- 'Join' should be translated using the same localized wording YouTube displays.
This appears in the video player for certain videos. -->
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
<!-- '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. -->
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
This button usually appears when searching for a YT creator. -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<!-- 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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<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">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
</patch>
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
</app>
</resources>

View File

@@ -0,0 +1,272 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_reset">Restablir</string>
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">Quant a</string>
</patch>
<patch id="misc.debugging.DebuggingPatch">
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<!-- 'Join' should be translated using the same localized wording YouTube displays.
This appears in the video player for certain videos. -->
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
<!-- '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. -->
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
This button usually appears when searching for a YT creator. -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<!-- 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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<string name="revanced_ryd_about">Quant a</string>
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<patch id="layout.sponsorblock.SponsorBlockResourcePatch">
<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>
<string name="revanced_sb_about">Quant a</string>
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<string name="revanced_start_page_entry_0">Per defecte</string>
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
</patch>
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
<string name="revanced_block_embedded_ads_entry_1">Desactivat</string>
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
</patch>
</app>
</resources>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,277 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Note: All strings must have a unique path, even if the same string is declared in two different apps.
This is because Crowdin requires temporarily flattening this file and removing the <app> and <patch> elements.
# General guidelines and information for translating
## Strings parameters can be reordered to allow more flexible translations if the grammar should be changed.
For example, the patches string:
<string name="revanced_patches_string">You will arrive at %1$s in %2$s hours from now</string>
Could be translated to another language using a rearranged grammar:
<string name="revanced_patches_string">You will arrive %2$s hours from now at %1$s</string>
For Manager strings:
You will arrive at ${destination} in ${count} hours from now
Could be rearranged by changing the order of the ${} parameters:
You will arrive ${count} hours from now at ${destination}
Reordering is particularly relevant when translating into right to left languages, or for any language with grammar that is noticeably different from English.
## Single and double quotation marks must be escaped for patch strings (Manager does not require escaping any quotes).
All _patches_ single and double quotation marks must be escaped as \" or \'
Forgetting to do this will cause that string to appear in app with no quotation characters.
Correct:
<string name="revanced_string">You\'re correct. This is the \"correct\" way and this text will appear as expected in the app</string>
Not correct:
<string name="revanced_string">You're not correct. This is not the "correct" way and this text will not appear as expected the in app</string>
-->
<resources>
<app id="shared">
<patch id="misc.settings.BaseSettingsResourcePatch">
<string name="revanced_settings_reset">Lähtesta</string>
</patch>
<patch id="misc.gms.BaseGmsCoreSupportResourcePatch">
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
</app>
<app id="youtube">
<patch id="misc.settings.SettingsResourcePatch">
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_settings_screen_00_about_title">Teave</string>
<string name="revanced_settings_screen_11_misc_title">Muud</string>
</patch>
<patch id="misc.debugging.DebuggingPatch">
</patch>
<patch id="layout.hide.general.HideLayoutComponentsPatch">
<!-- 'Join' should be translated using the same localized wording YouTube displays.
This appears in the video player for certain videos. -->
<!-- 'For you' should be translated using the same localized wording YouTube displays. -->
<!-- '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. -->
<!-- 'People also watch' should be translated using the same localized wording YouTube displays. -->
<!-- 'Show more' should be translated with the same localized wording that YouTube displays.
This button usually appears when searching for a YT creator. -->
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
<!-- For localization it is preferred, but not required, if 'LeBlanc' is replaced with a localized name or a familiar word that has upper case letters in the middle of the word.
This is because keywords can be in any language, and showing an example in the localized script helps convey this. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.general.HideAdsResourcePatch">
<!-- 'Visit store' should be translated with the same localized wording that YouTube displays. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="ad.getpremium.HideGetPremiumPatch">
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="interaction.copyvideourl.CopyVideoUrlResourcePatch">
</patch>
<patch id="interaction.dialog.RemoveViewerDiscretionDialogPatch">
</patch>
<patch id="interaction.downloads.DownloadsResourcePatch">
<!-- 'download action button' should be translated using the same wording as the translation of 'revanced_hide_download_button_title' -->
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
</patch>
<patch id="interaction.seekbar.EnableSeekbarTappingPatch">
</patch>
<patch id="interaction.swipecontrols.SwipeControlsResourcePatch">
</patch>
<patch id="layout.autocaptions.AutoCaptionsPatch">
</patch>
<patch id="layout.buttons.action.HideButtonsPatch">
<!-- 'Share' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Report' should be translated with the same localized wording that YouTube displays.
This button usually appears only on live streams. -->
<!-- 'Remix' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Download' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Thanks' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Clip' should be translated with the same localized wording that YouTube displays. -->
<!-- 'Save' should be translated with the same localized wording that YouTube displays. -->
</patch>
<patch id="layout.buttons.autoplay.HideAutoplayButtonPatch">
</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' -->
</patch>
<patch id="layout.buttons.cast.HideCastButtonPatch">
</patch>
<patch id="layout.buttons.navigation.NavigationButtonsPatch">
<!-- 'Home' should be translated using the same localized wording YouTube displays for the tab. -->
<!-- 'Shorts' should be translated using the same localized wording YouTube displays the tab. -->
<!-- The Create button has no display name. Translate normally. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays the tab. -->
<!-- 'Notifications' should be translated using the same localized wording YouTube displays the tab. -->
</patch>
<patch id="layout.hide.player.flyoutmenupanel.HidePlayerFlyoutMenuPatch">
<!-- 'Captions' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Additional settings' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Loop video' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Ambient mode' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Help & feedback' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Playback speed' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- '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. -->
<!-- 'Lock screen' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Audio track' should be translated using the same localized wording YouTube displays for the menu item. -->
<!-- 'Watch in VR' should be translated using the same localized wording YouTube displays for the menu item. -->
</patch>
<patch id="layout.buttons.player.hide.HidePlayerButtonsPatch">
</patch>
<patch id="layout.hide.albumcards.AlbumCardsResourcePatch">
</patch>
<patch id="layout.hide.comments.CommentsPatch">
</patch>
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
</patch>
<patch id="layout.hide.endscreencards.HideEndscreenCardsResourcePatch">
</patch>
<patch id="layout.hide.filterbar.HideFilterBarResourcePatch">
</patch>
<patch id="layout.hide.floatingmicrophone.HideFloatingMicrophoneButtonResourcePatch">
</patch>
<patch id="layout.hide.fullscreenambientmode.DisableFullscreenAmbientModePatch">
</patch>
<patch id="layout.hide.infocards.HideInfocardsResourcePatch">
<string name="revanced_hide_info_cards_summary_on">Infokaardid on peidetud</string>
<string name="revanced_hide_info_cards_summary_off">Infokaardid on nähtaval</string>
</patch>
<patch id="layout.hide.rollingnumber.DisableRollingNumberAnimationPatch">
</patch>
<patch id="layout.hide.seekbar.HideSeekbarPatch">
</patch>
<patch id="layout.hide.shorts.HideShortsComponentsResourcePatch">
<!-- '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. -->
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'subscribe' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'remix' should be translated using the same localized wording YouTube displays for the button. -->
<!-- 'share' should be translated using the same localized wording YouTube displays for the button. -->
</patch>
<patch id="layout.hide.suggestedvideoendscreen.DisableSuggestedVideoEndScreenResourcePatch">
</patch>
<patch id="layout.hide.time.HideTimestampPatch">
</patch>
<patch id="layout.panels.popup.PlayerPopupPanelsPatch">
</patch>
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
</patch>
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
<!-- 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. -->
<!-- Toast shown if the user enables RYD while a video is opened, and then tries to vote for the video. -->
<!-- Translations should use language similar to 'revanced_sb_enable_compact_skip_button' -->
<string name="revanced_ryd_about">Teave</string>
<!-- Statistic strings are shown in the settings only when ReVanced debug mode is enabled. Typical users will never see these. -->
</patch>
<patch id="layout.searchbar.WideSearchbarPatch">
</patch>
<patch id="layout.seekbar.RestoreOldSeekbarThumbnailsPatch">
</patch>
<patch id="layout.sponsorblock.SponsorBlockResourcePatch">
<string name="revanced_sb_appearance_category">Välimus</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">Laen...</string>
<string name="revanced_sb_reset">Lähtesta</string>
<string name="revanced_sb_about">Teave</string>
</patch>
<patch id="layout.spoofappversion.SpoofAppVersionPatch">
<!-- It is ideal, but not required, if the text here appears is alphabetically after the text used for 'revanced_spoof_app_version_title'.
This is because the 'General layout' menu uses alphabetic sorting, and it functionally works better if the spoof target selector appears below the 'Spoof app version' UI switch -->
<!-- 'RYD' is 'Return YouTube Dislike' -->
</patch>
<patch id="layout.startpage.ChangeStartPagePatch">
<string name="revanced_start_page_entry_0">Vaikimisi</string>
<!-- 'Home' should be translated using the same localized wording YouTube displays for the home tab. -->
<!-- 'Subscriptions' should be translated using the same localized wording YouTube displays for the subscriptions tab. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- 'History' should be translated using the same localized wording YouTube displays for the 'history' section in the 'You' tab. -->
</patch>
<patch id="layout.startupshortsreset.DisableResumingShortsOnStartupPatch">
</patch>
<patch id="layout.tablet.EnableTabletLayoutPatch">
</patch>
<patch id="layout.miniplayer.MiniplayerPatch">
</patch>
<patch id="layout.theme.ThemeBytecodePatch">
</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. -->
<!-- 'You' should be translated using the same localized wording YouTube displays for the You (library) tab. -->
<!-- Translations of this should not be longer than the original English text, otherwise the text can be clipped and not entirely shown. -->
</patch>
<patch id="misc.announcements.AnnouncementsPatch">
<string name="revanced_announcements_dialog_dismiss">Loobu</string>
</patch>
<patch id="misc.autorepeat.AutoRepeatPatch">
</patch>
<patch id="misc.dimensions.spoof.SpoofDeviceDimensionsPatch">
</patch>
<patch id="misc.gms.GmsCoreSupportResourcePatch">
</patch>
<patch id="misc.links.BypassURLRedirectsPatch">
</patch>
<patch id="misc.links.OpenLinksExternallyPatch">
</patch>
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
</patch>
<patch id="misc.zoomhaptics.ZoomHapticsPatch">
</patch>
<patch id="video.quality.RememberVideoQualityPatch">
</patch>
<patch id="video.speed.button.PlaybackSpeedButtonPatch">
</patch>
<patch id="video.speed.custom.CustomPlaybackSpeedPatch">
</patch>
<patch id="video.speed.remember.RememberPlaybackSpeedPatch">
</patch>
<patch id="video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch">
</patch>
<patch id="interaction.seekbar.EnableSlideToSeekPatch">
</patch>
<patch id="misc.fix.playback.SpoofClientPatch">
</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">
</patch>
<!-- This patch is no longer used and these strings will soon be deleted. -->
<patch id="video.hdrbrightness.HDRBrightnessPatch">
</patch>
</app>
<app id="twitch">
<patch id="ad.audio.AudioAdsPatch">
</patch>
<patch id="ad.embedded.EmbeddedAdsPatch">
<string name="revanced_block_embedded_ads_entry_1">Väljas</string>
</patch>
<patch id="ad.video.VideoAdsPatch">
</patch>
<patch id="chat.antidelete.ShowDeletedMessagesPatch">
</patch>
<patch id="chat.autoclaim.AutoClaimChannelPointsPatch">
</patch>
<patch id="debug.DebugModePatch">
<!-- Twitch specific internal debug mode, and not the same as 'revanced_debug_title' -->
</patch>
<patch id="misc.settings.SettingsPatch">
<string name="revanced_misc_screen_title">Muud</string>
</patch>
</app>
</resources>

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