mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-15 21:52:27 +01:00
Compare commits
59 Commits
v4.9.0-dev
...
v4.11.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d02a490f36 | ||
|
|
f0fb2fa3ba | ||
|
|
4885d4ef00 | ||
|
|
a036c1fa0a | ||
|
|
a81a6bf5b2 | ||
|
|
81836119c0 | ||
|
|
def1ec4de6 | ||
|
|
72f02c8d2f | ||
|
|
5e0dd932cd | ||
|
|
dd6a9f977f | ||
|
|
7d4c2e820c | ||
|
|
e4ae9ccd26 | ||
|
|
d469604f0f | ||
|
|
1fa7dc83a7 | ||
|
|
f5f024024a | ||
|
|
c5f0bc41e2 | ||
|
|
a80825cbc2 | ||
|
|
55556f3efc | ||
|
|
70e54f8794 | ||
|
|
e2f9193aa8 | ||
|
|
decdff9037 | ||
|
|
8f6519d206 | ||
|
|
b0b809d222 | ||
|
|
979af7ddd0 | ||
|
|
0b098a2027 | ||
|
|
2bfd75ce96 | ||
|
|
047e6d994b | ||
|
|
03eb9c032a | ||
|
|
dfc14c1a26 | ||
|
|
20dedb2605 | ||
|
|
cb7a283be1 | ||
|
|
7fa7ef6c4f | ||
|
|
5a93660825 | ||
|
|
e5ced6310d | ||
|
|
1147094241 | ||
|
|
f0cc415199 | ||
|
|
c0f8ddac52 | ||
|
|
3cfe745d59 | ||
|
|
550ac09e32 | ||
|
|
e2409213d4 | ||
|
|
a8b14d560f | ||
|
|
d5c0b5ed65 | ||
|
|
343fdec796 | ||
|
|
2ea583c220 | ||
|
|
8dda8988ef | ||
|
|
b575fc68ff | ||
|
|
c979e92676 | ||
|
|
b78b7cfe6c | ||
|
|
4919cba478 | ||
|
|
1d46b95698 | ||
|
|
70013d813b | ||
|
|
8a33fe9986 | ||
|
|
ee21a2bb91 | ||
|
|
ea67466bd5 | ||
|
|
320e039a9f | ||
|
|
6b9c13d92c | ||
|
|
8e67cdca55 | ||
|
|
32c5fa4d04 | ||
|
|
61401c9ea4 |
6
.github/workflows/open_pull_request.yml
vendored
6
.github/workflows/open_pull_request.yml
vendored
@@ -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
|
||||
|
||||
57
.github/workflows/pull_strings.yml
vendored
57
.github/workflows/pull_strings.yml
vendored
@@ -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@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 }}
|
||||
|
||||
44
.github/workflows/push_strings.yml
vendored
44
.github/workflows/push_strings.yml
vendored
@@ -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@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 }}
|
||||
|
||||
194
CHANGELOG.md
194
CHANGELOG.md
@@ -1,3 +1,197 @@
|
||||
# [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **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))
|
||||
|
||||
# [4.10.0](https://github.com/ReVanced/revanced-patches/compare/v4.9.0...v4.10.0) (2024-06-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Correct invalid string name ([b84494f](https://github.com/ReVanced/revanced-patches/commit/b84494f4e26e040ada69ed7a516f331f2d47da87))
|
||||
* **YouTube - Client spoof:** Correctly play more livestreams using Android VR ([#3316](https://github.com/ReVanced/revanced-patches/issues/3316)) ([c05264a](https://github.com/ReVanced/revanced-patches/commit/c05264af3944cbfe8d9aa34fb0e0fddb05a1d42f))
|
||||
* **YouTube - Hide description components:** Replace `Hide game section` and `Hide music section` with `Hide attributes section` ([#3327](https://github.com/ReVanced/revanced-patches/issues/3327)) ([0198a43](https://github.com/ReVanced/revanced-patches/commit/0198a436f97b127a2a5dd283644254f9a0ae3e43))
|
||||
* **YouTube Music:** Rename `Minimized playback` to `Remove background playback restrictions` ([#3315](https://github.com/ReVanced/revanced-patches/issues/3315)) ([3c31e55](https://github.com/ReVanced/revanced-patches/commit/3c31e55b13d9495e857f068f8cd2b4320112d763))
|
||||
* **YouTube:** Rename `Minimized playback` to `Remove background playback restrictions` ([#3314](https://github.com/ReVanced/revanced-patches/issues/3314)) ([37d415b](https://github.com/ReVanced/revanced-patches/commit/37d415b53af4771d9c97a8b1c153be32bf3ac2e0))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Change version code` patch ([#3338](https://github.com/ReVanced/revanced-patches/issues/3338)) ([685ef39](https://github.com/ReVanced/revanced-patches/commit/685ef39119daf1033a83262982519531c481c40f))
|
||||
* **Boost For Reddit:** Add `Fix /s/ links` patch ([#3154](https://github.com/ReVanced/revanced-patches/issues/3154)) ([5fa9fd2](https://github.com/ReVanced/revanced-patches/commit/5fa9fd2dfef43838d7311a967a3e805256a5d116))
|
||||
* **Boost for Reddit:** Add `Fix audio missing in video downloads` patch ([#3287](https://github.com/ReVanced/revanced-patches/issues/3287)) ([a9258d4](https://github.com/ReVanced/revanced-patches/commit/a9258d48d3ddf8552ab56219677a3b31ee553666))
|
||||
* **YouTube - Comments:** Add `Hide 'Create a Short' button` option ([#3333](https://github.com/ReVanced/revanced-patches/issues/3333)) ([be9e244](https://github.com/ReVanced/revanced-patches/commit/be9e24420fda80903e44e2e2278ea4904ecac4e1))
|
||||
* **YouTube - Comments:** Add `Hide Thanks button` and `Hide 'Comments by members' header` options ([#3317](https://github.com/ReVanced/revanced-patches/issues/3317)) ([9c4c4f0](https://github.com/ReVanced/revanced-patches/commit/9c4c4f05a762d745404101bbc3925ab4eba2deb8))
|
||||
* **YouTube - Miniplayer:** Rename `Tablet mini player` and allow selecting the style of the in-app miniplayer ([#3302](https://github.com/ReVanced/revanced-patches/issues/3302)) ([5511736](https://github.com/ReVanced/revanced-patches/commit/5511736b0c5dd409db6a68db0f85e389bb95be47))
|
||||
|
||||
# [4.10.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.9...v4.10.0-dev.10) (2024-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Correct invalid string name ([b84494f](https://github.com/ReVanced/revanced-patches/commit/b84494f4e26e040ada69ed7a516f331f2d47da87))
|
||||
|
||||
# [4.10.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.8...v4.10.0-dev.9) (2024-06-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide description components:** Replace `Hide game section` and `Hide music section` with `Hide attributes section` ([#3327](https://github.com/ReVanced/revanced-patches/issues/3327)) ([0198a43](https://github.com/ReVanced/revanced-patches/commit/0198a436f97b127a2a5dd283644254f9a0ae3e43))
|
||||
|
||||
# [4.10.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.7...v4.10.0-dev.8) (2024-06-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Comments:** Add `Hide 'Create a Short' button` option ([#3333](https://github.com/ReVanced/revanced-patches/issues/3333)) ([be9e244](https://github.com/ReVanced/revanced-patches/commit/be9e24420fda80903e44e2e2278ea4904ecac4e1))
|
||||
|
||||
# [4.10.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.6...v4.10.0-dev.7) (2024-06-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Change version code` patch ([#3338](https://github.com/ReVanced/revanced-patches/issues/3338)) ([685ef39](https://github.com/ReVanced/revanced-patches/commit/685ef39119daf1033a83262982519531c481c40f))
|
||||
|
||||
# [4.10.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.5...v4.10.0-dev.6) (2024-06-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Comments:** Add `Hide Thanks button` and `Hide 'Comments by members' header` options ([#3317](https://github.com/ReVanced/revanced-patches/issues/3317)) ([9c4c4f0](https://github.com/ReVanced/revanced-patches/commit/9c4c4f05a762d745404101bbc3925ab4eba2deb8))
|
||||
|
||||
# [4.10.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.4...v4.10.0-dev.5) (2024-06-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Client spoof:** Correctly play more livestreams using Android VR ([#3316](https://github.com/ReVanced/revanced-patches/issues/3316)) ([c05264a](https://github.com/ReVanced/revanced-patches/commit/c05264af3944cbfe8d9aa34fb0e0fddb05a1d42f))
|
||||
|
||||
# [4.10.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.3...v4.10.0-dev.4) (2024-06-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Boost for Reddit:** Add `Fix audio missing in video downloads` patch ([#3287](https://github.com/ReVanced/revanced-patches/issues/3287)) ([a9258d4](https://github.com/ReVanced/revanced-patches/commit/a9258d48d3ddf8552ab56219677a3b31ee553666))
|
||||
|
||||
# [4.10.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.2...v4.10.0-dev.3) (2024-06-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Boost For Reddit:** Add `Fix /s/ links` patch ([#3154](https://github.com/ReVanced/revanced-patches/issues/3154)) ([5fa9fd2](https://github.com/ReVanced/revanced-patches/commit/5fa9fd2dfef43838d7311a967a3e805256a5d116))
|
||||
|
||||
# [4.10.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.1...v4.10.0-dev.2) (2024-06-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music:** Rename `Minimized playback` to `Remove background playback restrictions` ([#3315](https://github.com/ReVanced/revanced-patches/issues/3315)) ([3c31e55](https://github.com/ReVanced/revanced-patches/commit/3c31e55b13d9495e857f068f8cd2b4320112d763))
|
||||
* **YouTube:** Rename `Minimized playback` to `Remove background playback restrictions` ([#3314](https://github.com/ReVanced/revanced-patches/issues/3314)) ([37d415b](https://github.com/ReVanced/revanced-patches/commit/37d415b53af4771d9c97a8b1c153be32bf3ac2e0))
|
||||
|
||||
# [4.10.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.9.0...v4.10.0-dev.1) (2024-06-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Miniplayer:** Rename `Tablet mini player` and allow selecting the style of the in-app miniplayer ([#3302](https://github.com/ReVanced/revanced-patches/issues/3302)) ([5511736](https://github.com/ReVanced/revanced-patches/commit/5511736b0c5dd409db6a68db0f85e389bb95be47))
|
||||
|
||||
# [4.9.0](https://github.com/ReVanced/revanced-patches/compare/v4.8.3...v4.9.0) (2024-06-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof client:** Allow swipe gestures to enter/exit fullscreen when spoofing with `Android VR` client ([#3259](https://github.com/ReVanced/revanced-patches/issues/3259)) ([5114900](https://github.com/ReVanced/revanced-patches/commit/5114900b1b5572c04ba6759eedab77f0a934b058))
|
||||
* **YouTube - Spoof client:** Restore playback speed menu when spoofing to an iOS client ([95f290f](https://github.com/ReVanced/revanced-patches/commit/95f290f1139cc8679beecac53c623847668f885e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Messenger:** Add `Hide inbox subtabs` patch ([#3163](https://github.com/ReVanced/revanced-patches/issues/3163)) ([24e4ebd](https://github.com/ReVanced/revanced-patches/commit/24e4ebd77ad0f349b479926bf3983b72c2683496))
|
||||
* **YouTube - Hide layout components:** Disable like / subscribe button glow animation ([#3265](https://github.com/ReVanced/revanced-patches/issues/3265)) ([68d35ea](https://github.com/ReVanced/revanced-patches/commit/68d35eafc15513c23cd5220260023e7ec5b7978a))
|
||||
* **YouTube - Playback speed:** Add option to show speed dialog button in video player ([#3197](https://github.com/ReVanced/revanced-patches/issues/3197)) ([ad00305](https://github.com/ReVanced/revanced-patches/commit/ad00305ff57d5e8041de7375bea7d3ad6f18c4e2))
|
||||
* **YouTube Music:** Support version `7.03` ([#3272](https://github.com/ReVanced/revanced-patches/issues/3272)) ([d1ceca3](https://github.com/ReVanced/revanced-patches/commit/d1ceca39984f7933b28d81802d04bb3ead327595))
|
||||
* **YouTube:** Support version `19.12`, `19.13`, `19.14`, `19.15` and `19.16` ([#3239](https://github.com/ReVanced/revanced-patches/issues/3239)) ([99b07e0](https://github.com/ReVanced/revanced-patches/commit/99b07e0e18574668f36bb3c962c8d11222114be4))
|
||||
|
||||
# [4.9.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.6...v4.9.0-dev.7) (2024-06-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Playback speed:** Add option to show speed dialog button in video player ([#3197](https://github.com/ReVanced/revanced-patches/issues/3197)) ([ad00305](https://github.com/ReVanced/revanced-patches/commit/ad00305ff57d5e8041de7375bea7d3ad6f18c4e2))
|
||||
|
||||
# [4.9.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.5...v4.9.0-dev.6) (2024-06-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Spoof client:** Restore playback speed menu when spoofing to an iOS client ([95f290f](https://github.com/ReVanced/revanced-patches/commit/95f290f1139cc8679beecac53c623847668f885e))
|
||||
|
||||
# [4.9.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.4...v4.9.0-dev.5) (2024-06-01)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -115,11 +118,11 @@ with the maintainers of ReVanced Patches. This will help you determine whether y
|
||||
and whether it is worth your time to implement it
|
||||
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
|
||||
3. Commit your changes. In case you are contributing a new patch, make sure to follow the conventions for patches
|
||||
described in the [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs)
|
||||
described in the [ReVanced Patcher documentation](https://github.com/ReVanced/revanced-patcher/tree/main/docs)
|
||||
4. Submit a pull request to the `dev` branch of the repository and reference issues
|
||||
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
|
||||
|
||||
@@ -105,6 +105,12 @@ public final class app/revanced/patches/all/misc/transformation/IMethodCall$Defa
|
||||
public static fun replaceInvokeVirtualWithIntegrations (Lapp/revanced/patches/all/misc/transformation/IMethodCall;Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lcom/android/tools/smali/dexlib2/iface/instruction/formats/Instruction35c;I)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/versioncode/ChangeVersionCodePatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/misc/versioncode/ChangeVersionCodePatch;
|
||||
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/screencapture/removerestriction/RemoveCaptureRestrictionPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch;
|
||||
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;
|
||||
@@ -149,6 +155,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;
|
||||
@@ -169,6 +181,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
|
||||
@@ -235,6 +253,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
|
||||
@@ -403,6 +427,12 @@ public final class app/revanced/patches/music/misc/androidauto/BypassCertificate
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/backgroundplayback/BackgroundPlaybackPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/misc/backgroundplayback/BackgroundPlaybackPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/gms/Constants {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/misc/gms/Constants;
|
||||
}
|
||||
@@ -511,6 +541,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
|
||||
@@ -529,6 +569,18 @@ public final class app/revanced/patches/reddit/ad/general/HideAdsPatch : app/rev
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/reddit/customclients/BaseFixSLinksPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Ljava/util/Set;)V
|
||||
public synthetic fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
protected abstract fun getIntegrationsClassDescriptor ()Ljava/lang/String;
|
||||
protected final fun getResolveSLinkMethod ()Ljava/lang/String;
|
||||
protected final fun getSetAccessTokenMethod ()Ljava/lang/String;
|
||||
protected abstract fun patchNavigationHandler (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
protected abstract fun patchSetAccessToken (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/reddit/customclients/BaseSpoofClientPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public fun <init> (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
@@ -564,6 +616,20 @@ public final class app/revanced/patches/reddit/customclients/boostforreddit/api/
|
||||
public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch : app/revanced/patches/reddit/customclients/BaseFixSLinksPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch;
|
||||
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -642,10 +708,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/detec
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patches/reddit/customclients/BaseFixSLinksPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
@@ -970,6 +1038,18 @@ 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/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
|
||||
@@ -994,6 +1074,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
|
||||
@@ -1528,6 +1620,12 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch;
|
||||
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/layout/panels/popup/PlayerPopupPanelsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1632,6 +1730,12 @@ public final class app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch;
|
||||
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/debugging/DebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/debugging/DebuggingPatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
@@ -1840,6 +1944,12 @@ public final class app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch :
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/video/speed/button/PlaybackSpeedButtonPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/video/speed/button/PlaybackSpeedButtonPatch;
|
||||
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/video/speed/custom/CustomPlaybackSpeedPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
@@ -1888,6 +1998,7 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat
|
||||
public final class app/revanced/util/BytecodeUtilsKt {
|
||||
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
|
||||
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
|
||||
public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException;
|
||||
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
|
||||
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I
|
||||
@@ -1895,6 +2006,7 @@ public final class app/revanced/util/BytecodeUtilsKt {
|
||||
public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
|
||||
public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
|
||||
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||
public static final fun indexOfFirstWideLiteralInstructionValueOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||
public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
kotlin.code.style = official
|
||||
version = 4.9.0-dev.5
|
||||
version = 4.11.0-dev.7
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package app.revanced.patches.all.misc.versioncode
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.intPatchOption
|
||||
import app.revanced.util.getNode
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Patch(
|
||||
name = "Change version code",
|
||||
description = "Changes the version code of the app. By default the highest version code is set. " +
|
||||
"This allows older versions of an app to be installed " +
|
||||
"if their version code is set to the same or a higher value and can stop app stores to update the app.",
|
||||
use = false,
|
||||
)
|
||||
@Suppress("unused")
|
||||
object ChangeVersionCodePatch : ResourcePatch() {
|
||||
private val versionCode by intPatchOption(
|
||||
key = "versionCode",
|
||||
default = Int.MAX_VALUE,
|
||||
values = mapOf(
|
||||
"Lowest" to 1,
|
||||
"Highest" to Int.MAX_VALUE,
|
||||
),
|
||||
title = "Version code",
|
||||
description = "The version code to use",
|
||||
required = true,
|
||||
) {
|
||||
it!! >= 1
|
||||
}
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
context.document["AndroidManifest.xml"].use { document ->
|
||||
val manifestElement = document.getNode("manifest") as Element
|
||||
manifestElement.setAttribute("android:versionCode", "$versionCode")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"),
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package app.revanced.patches.instagram.patches.ad.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object AdInjectorFingerprint : MethodFingerprint(
|
||||
returnType = "Z",
|
||||
accessFlags = AccessFlags.PRIVATE.value,
|
||||
parameters = listOf("L", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
),
|
||||
strings = listOf("SponsoredContentController::Delivery"),
|
||||
)
|
||||
@@ -1,50 +1,13 @@
|
||||
package app.revanced.patches.music.layout.minimizedplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.music.layout.minimizedplayback.fingerprints.BackgroundPlaybackDisableFingerprint
|
||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patches.music.misc.backgroundplayback.BackgroundPlaybackPatch
|
||||
|
||||
@Patch(
|
||||
name = "Minimized playback",
|
||||
description = "Unlocks options for picture-in-picture and background playback.",
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.apps.youtube.music",
|
||||
[
|
||||
"6.45.54",
|
||||
"6.51.53",
|
||||
"7.01.53",
|
||||
"7.02.52",
|
||||
"7.03.52",
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
@Deprecated("This patch has been merged into BackgroundPlaybackPatch.")
|
||||
object MinimizedPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint,
|
||||
BackgroundPlaybackDisableFingerprint,
|
||||
),
|
||||
dependencies = setOf(BackgroundPlaybackPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"return-void",
|
||||
) ?: throw KidsMinimizedPlaybackPolicyControllerFingerprint.exception
|
||||
|
||||
BackgroundPlaybackDisableFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""",
|
||||
) ?: throw BackgroundPlaybackDisableFingerprint.exception
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package app.revanced.patches.music.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.music.misc.backgroundplayback.fingerprints.BackgroundPlaybackDisableFingerprint
|
||||
import app.revanced.patches.music.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
name = "Remove background playback restrictions",
|
||||
description = "Removes restrictions on background playback, including playing kids videos in the background.",
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.apps.youtube.music",
|
||||
[
|
||||
"6.45.54",
|
||||
"6.51.53",
|
||||
"7.01.53",
|
||||
"7.02.52",
|
||||
"7.03.52",
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object BackgroundPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint,
|
||||
BackgroundPlaybackDisableFingerprint,
|
||||
),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"return-void",
|
||||
)
|
||||
|
||||
BackgroundPlaybackDisableFingerprint.resultOrThrow().mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.music.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@@ -1,11 +1,11 @@
|
||||
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.music.misc.backgroundplayback.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 KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
internal object KidsBackgroundPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("I", "L", "Z"),
|
||||
@@ -2,10 +2,11 @@ package app.revanced.patches.music.premium.backgroundplay
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patches.music.layout.minimizedplayback.MinimizedPlaybackPatch
|
||||
@Deprecated("This patch has been merged into MinimizedPlaybackPatch.")
|
||||
import app.revanced.patches.music.misc.backgroundplayback.BackgroundPlaybackPatch
|
||||
|
||||
@Deprecated("This patch has been merged into BackgroundPlaybackPatch.")
|
||||
object BackgroundPlayPatch : BytecodePatch(
|
||||
dependencies = setOf(MinimizedPlaybackPatch::class),
|
||||
dependencies = setOf(BackgroundPlaybackPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
package app.revanced.patches.reddit.customclients
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
abstract class BaseFixSLinksPatch(
|
||||
private val handleNavigationFingerprint: MethodFingerprint,
|
||||
private val setAccessTokenFingerprint: MethodFingerprint,
|
||||
compatiblePackages: Set<CompatiblePackage>,
|
||||
dependencies: Set<PatchClass> = emptySet(),
|
||||
) : BytecodePatch(
|
||||
name = "Fix /s/ links",
|
||||
fingerprints = setOf(handleNavigationFingerprint, setAccessTokenFingerprint),
|
||||
compatiblePackages = compatiblePackages,
|
||||
dependencies = dependencies,
|
||||
) {
|
||||
protected abstract val integrationsClassDescriptor: String
|
||||
|
||||
protected val resolveSLinkMethod =
|
||||
"patchResolveSLink(Ljava/lang/String;)Z"
|
||||
|
||||
protected val setAccessTokenMethod =
|
||||
"patchSetAccessToken(Ljava/lang/String;)V"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
handleNavigationFingerprint.resultOrThrow().patchNavigationHandler(context)
|
||||
setAccessTokenFingerprint.resultOrThrow().patchSetAccessToken(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch app's navigation handler to resolve /s/ links.
|
||||
*
|
||||
* @param context The current [BytecodeContext].
|
||||
*
|
||||
*/
|
||||
protected abstract fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext)
|
||||
|
||||
/**
|
||||
* Patch access token setup in app to resolve /s/ links with an access token
|
||||
* in order to bypass API bans when making unauthorized requests.
|
||||
*
|
||||
* @param context The current [BytecodeContext].
|
||||
*/
|
||||
protected abstract fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads
|
||||
|
||||
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.reddit.customclients.boostforreddit.fix.downloads.fingerprints.DownloadAudioFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
name = "Fix missing audio in video downloads",
|
||||
description = "Fixes audio missing in videos downloaded from v.redd.it.",
|
||||
compatiblePackages = [CompatiblePackage("com.rubenmayayo.reddit")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object FixAudioMissingInDownloadsPatch : BytecodePatch(
|
||||
setOf(DownloadAudioFingerprint),
|
||||
) {
|
||||
private val endpointReplacements = mapOf(
|
||||
"/DASH_audio.mp4" to "/DASH_AUDIO_128.mp4",
|
||||
"/audio" to "/DASH_AUDIO_64.mp4",
|
||||
)
|
||||
override fun execute(context: BytecodeContext) {
|
||||
DownloadAudioFingerprint.resultOrThrow().let { result ->
|
||||
result.scanResult.stringsScanResult!!.matches.forEach { match ->
|
||||
result.mutableMethod.apply {
|
||||
val replacement = endpointReplacements[match.string]
|
||||
val register = getInstruction<OneRegisterInstruction>(match.index).registerA
|
||||
|
||||
replaceInstruction(match.index, "const-string v$register, \"$replacement\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object DownloadAudioFingerprint : MethodFingerprint(
|
||||
strings = setOf("/DASH_audio.mp4", "/audio"),
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink
|
||||
|
||||
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.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.reddit.customclients.BaseFixSLinksPatch
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints.GetOAuthAccessTokenFingerprint
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints.HandleNavigationFingerprint
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.IntegrationsPatch
|
||||
|
||||
@Suppress("unused")
|
||||
object FixSLinksPatch : BaseFixSLinksPatch(
|
||||
handleNavigationFingerprint = HandleNavigationFingerprint,
|
||||
setAccessTokenFingerprint = GetOAuthAccessTokenFingerprint,
|
||||
compatiblePackages = setOf(CompatiblePackage("com.rubenmayayo.reddit")),
|
||||
dependencies = setOf(IntegrationsPatch::class),
|
||||
) {
|
||||
override val integrationsClassDescriptor = "Lapp/revanced/integrations/boostforreddit/FixSLinksPatch;"
|
||||
|
||||
override fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) {
|
||||
mutableMethod.apply {
|
||||
val urlRegister = "p1"
|
||||
val tempRegister = "v1"
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { $urlRegister }, $integrationsClassDescriptor->$resolveSLinkMethod
|
||||
move-result $tempRegister
|
||||
if-eqz $tempRegister, :continue
|
||||
return $tempRegister
|
||||
""",
|
||||
ExternalLabel("continue", getInstruction(0)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) = mutableMethod.addInstruction(
|
||||
3,
|
||||
"invoke-static { v0 }, $integrationsClassDescriptor->$setAccessTokenMethod",
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object GetOAuthAccessTokenFingerprint : MethodFingerprint(
|
||||
strings = listOf("access_token"),
|
||||
accessFlags = AccessFlags.PUBLIC.value,
|
||||
returnType = "Ljava/lang/String",
|
||||
customFingerprint = { _, classDef -> classDef.type == "Lnet/dean/jraw/http/oauth/OAuthData;" },
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object HandleNavigationFingerprint : MethodFingerprint(
|
||||
strings = listOf(
|
||||
"android.intent.action.SEARCH",
|
||||
"subscription",
|
||||
"sort",
|
||||
"period",
|
||||
"boostforreddit.com/themes",
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.fingerprints.InitFingerprint
|
||||
|
||||
@Patch(requiresIntegrations = true)
|
||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||
setOf(InitFingerprint)
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object InitFingerprint : IntegrationsFingerprint(
|
||||
customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/rubenmayayo/reddit/MyApplication;" && methodDef.name == "onCreate" },
|
||||
insertIndexResolver = { 1 } // Insert after call to super class.
|
||||
)
|
||||
@@ -1,32 +1,49 @@
|
||||
package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink
|
||||
|
||||
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.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.reddit.customclients.BaseFixSLinksPatch
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.LinkHelperOpenLinkFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.SetAuthorizationHeaderFingerprint
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.IntegrationsPatch
|
||||
|
||||
@Patch(
|
||||
name = "Fix /s/ links",
|
||||
description = "Fixes the issue where /s/ links do not work.",
|
||||
compatiblePackages = [
|
||||
@Suppress("unused")
|
||||
object FixSLinksPatch : BaseFixSLinksPatch(
|
||||
handleNavigationFingerprint = LinkHelperOpenLinkFingerprint,
|
||||
setAccessTokenFingerprint = SetAuthorizationHeaderFingerprint,
|
||||
compatiblePackages = setOf(
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync"),
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync.pro"),
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync.dev")
|
||||
],
|
||||
requiresIntegrations = true
|
||||
)
|
||||
object FixSLinksPatch : BytecodePatch(
|
||||
setOf(LinkHelperOpenLinkFingerprint)
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync.dev"),
|
||||
),
|
||||
dependencies = setOf(IntegrationsPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) =
|
||||
LinkHelperOpenLinkFingerprint.result?.mutableMethod?.addInstructions(
|
||||
1,
|
||||
"""
|
||||
invoke-static { p3 }, Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;->resolveSLink(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object p3
|
||||
"""
|
||||
) ?: throw LinkHelperOpenLinkFingerprint.exception
|
||||
override val integrationsClassDescriptor = "Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;"
|
||||
|
||||
override fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) {
|
||||
mutableMethod.apply {
|
||||
val urlRegister = "p3"
|
||||
val tempRegister = "v2"
|
||||
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { $urlRegister }, $integrationsClassDescriptor->$resolveSLinkMethod
|
||||
move-result $tempRegister
|
||||
if-eqz $tempRegister, :continue
|
||||
return $tempRegister
|
||||
""",
|
||||
ExternalLabel("continue", getInstruction(0)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) = mutableMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static { p0 }, $integrationsClassDescriptor->$setAccessTokenMethod",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object SetAuthorizationHeaderFingerprint : MethodFingerprint(
|
||||
strings = listOf("Authorization", "bearer "),
|
||||
returnType = "Ljava/util/HashMap;",
|
||||
customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/laurencedawson/reddit_sync/singleton/a;" },
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.fingerprints.InitFingerprint
|
||||
|
||||
@Patch(requiresIntegrations = true)
|
||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||
setOf(InitFingerprint)
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||
|
||||
internal object InitFingerprint : IntegrationsFingerprint(
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.type == "Lcom/laurencedawson/reddit_sync/RedditApplication;"
|
||||
},
|
||||
insertIndexResolver = { 1 }, // Insert after call to super class.
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
package app.revanced.patches.shared.misc.mapping
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import org.w3c.dom.Element
|
||||
import java.util.*
|
||||
@@ -51,9 +52,10 @@ object ResourceMappingPatch : ResourcePatch() {
|
||||
threadPoolExecutor.also { it.shutdown() }.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
operator fun get(type: String, name: String) = resourceMappings.first {
|
||||
it.type == type && it.name == name
|
||||
}.id
|
||||
operator fun get(type: String, name: String) =
|
||||
resourceMappings.firstOrNull {
|
||||
it.type == type && it.name == name
|
||||
}?.id ?: throw PatchException("Could not find resource type: $type name: $name")
|
||||
|
||||
data class ResourceElement(val type: String, val name: String, val id: Long)
|
||||
}
|
||||
|
||||
@@ -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.ad.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",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 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"
|
||||
},
|
||||
)
|
||||
@@ -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"
|
||||
},
|
||||
)
|
||||
@@ -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"
|
||||
},
|
||||
)
|
||||
@@ -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, \"\"")
|
||||
}
|
||||
@@ -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"
|
||||
},
|
||||
)
|
||||
@@ -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
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -62,9 +62,12 @@ object CommentsPatch : ResourcePatch() {
|
||||
PreferenceScreen(
|
||||
"revanced_comments_screen",
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_preview_comment"),
|
||||
SwitchPreference("revanced_hide_comments_by_members_header"),
|
||||
SwitchPreference("revanced_hide_comments_section"),
|
||||
SwitchPreference("revanced_hide_comment_timestamp_and_emoji_buttons")
|
||||
SwitchPreference("revanced_hide_comments_create_a_short_button"),
|
||||
SwitchPreference("revanced_hide_comments_preview_comment"),
|
||||
SwitchPreference("revanced_hide_comments_thanks_button"),
|
||||
SwitchPreference("revanced_hide_comments_timestamp_and_emoji_buttons")
|
||||
),
|
||||
sorting = PreferenceScreen.Sorting.UNSORTED
|
||||
)
|
||||
|
||||
@@ -94,16 +94,14 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||
PreferenceScreen(
|
||||
key = "revanced_hide_description_components_screen",
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_chapters"),
|
||||
SwitchPreference("revanced_hide_attributes_section"),
|
||||
SwitchPreference("revanced_hide_chapters_section"),
|
||||
SwitchPreference("revanced_hide_info_cards_section"),
|
||||
SwitchPreference("revanced_hide_game_section"),
|
||||
SwitchPreference("revanced_hide_music_section"),
|
||||
SwitchPreference("revanced_hide_podcast_section"),
|
||||
SwitchPreference("revanced_hide_transcript_section"),
|
||||
),
|
||||
),
|
||||
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"),
|
||||
@@ -144,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",
|
||||
@@ -156,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)
|
||||
|
||||
@@ -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"),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
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.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.InputType
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerClose
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerExpand
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerForwardButton
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerRewindButton
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.scrimOverlay
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlineXWhite24
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerDimensionsCalculatorParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernAddViewListenerFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernCloseButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernExpandButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernExpandCloseDrawablesFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernForwardButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernOverlayViewFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernRewindButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernViewParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerOverrideFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerOverrideNoContextFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerResponseModelSizeCheckFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||
import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.findOpcodeIndicesReversed
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
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.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
|
||||
// YT uses "Miniplayer" without a space between 'mini' and 'player: https://support.google.com/youtube/answer/9162927.
|
||||
@Patch(
|
||||
name = "Miniplayer",
|
||||
description = "Adds options to change the in app minimized player, " +
|
||||
"and if patching target 19.16+ adds options to use modern miniplayers.",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
MiniplayerResourcePatch::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 is left out, as it has incomplete miniplayer code and missing some UI resources.
|
||||
// It's simpler to not bother with supporting this single old version.
|
||||
// 19.15 has a different code for handling sub title texts,
|
||||
// and also probably not worth making changes just to support this single old version.
|
||||
"19.16.39" // Earliest supported version with modern miniplayers.
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object MiniplayerPatch : BytecodePatch(
|
||||
setOf(GetFormFactorFingerprint,
|
||||
MiniplayerDimensionsCalculatorParentFingerprint,
|
||||
MiniplayerResponseModelSizeCheckFingerprint,
|
||||
MiniplayerOverrideFingerprint,
|
||||
MiniplayerModernConstructorFingerprint,
|
||||
MiniplayerModernViewParentFingerprint,
|
||||
YouTubePlayerOverlaysLayoutFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/MiniplayerPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
// Modern mini player is only present and functional in 19.15+.
|
||||
// Resource is not present in older versions. Using it to determine, if patching an old version.
|
||||
val isPatchingOldVersion = ytOutlinePictureInPictureWhite24 < 0
|
||||
|
||||
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||
PreferenceScreen(
|
||||
key = "revanced_miniplayer_screen",
|
||||
sorting = Sorting.UNSORTED,
|
||||
preferences =
|
||||
if (isPatchingOldVersion) {
|
||||
setOf(
|
||||
ListPreference(
|
||||
"revanced_miniplayer_type",
|
||||
summaryKey = null,
|
||||
entriesKey = "revanced_miniplayer_type_legacy_entries",
|
||||
entryValuesKey = "revanced_miniplayer_type_legacy_entry_values"
|
||||
)
|
||||
)
|
||||
} else {
|
||||
setOf(
|
||||
ListPreference(
|
||||
"revanced_miniplayer_type",
|
||||
summaryKey = null,
|
||||
entriesKey = "revanced_miniplayer_type_19_15_entries",
|
||||
entryValuesKey = "revanced_miniplayer_type_19_15_entry_values"
|
||||
),
|
||||
SwitchPreference("revanced_miniplayer_hide_expand_close"),
|
||||
SwitchPreference("revanced_miniplayer_hide_subtext"),
|
||||
SwitchPreference("revanced_miniplayer_hide_rewind_forward"),
|
||||
TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// region Enable tablet miniplayer.
|
||||
|
||||
MiniplayerOverrideNoContextFingerprint.resolve(
|
||||
context,
|
||||
MiniplayerDimensionsCalculatorParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
MiniplayerOverrideNoContextFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Legacy tablet Miniplayer hooks.
|
||||
|
||||
MiniplayerOverrideFingerprint.resultOrThrow().let {
|
||||
val appNameStringIndex = it.scanResult.stringsScanResult!!.matches.first().index + 2
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val walkerMethod = context.toMethodWalker(this)
|
||||
.nextMethod(appNameStringIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
|
||||
walkerMethod.apply {
|
||||
findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MiniplayerResponseModelSizeCheckFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.insertLegacyTabletMiniplayerOverride(it.scanResult.patternScanResult!!.endIndex)
|
||||
}
|
||||
|
||||
if (isPatchingOldVersion) {
|
||||
// Return here, as patch below is only intended for new versions of the app.
|
||||
return
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
|
||||
// region Enable modern miniplayer.
|
||||
|
||||
MiniplayerModernConstructorFingerprint.resultOrThrow().mutableClass.methods.forEach {
|
||||
it.apply {
|
||||
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||
val iPutIndex = indexOfFirstInstructionOrThrow {
|
||||
this.opcode == Opcode.IPUT && this.getReference<FieldReference>()?.type == "I"
|
||||
}
|
||||
|
||||
insertModernMiniplayerTypeOverride(iPutIndex)
|
||||
} else {
|
||||
findReturnIndicesReversed().forEach { index -> insertModernMiniplayerOverride(index) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Fix 19.16 using mixed up drawables for tablet modern.
|
||||
// YT fixed this mistake in 19.17.
|
||||
// Fix this, by swapping the drawable resource values with each other.
|
||||
|
||||
MiniplayerModernExpandCloseDrawablesFingerprint.apply {
|
||||
resolve(
|
||||
context,
|
||||
MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
}.resultOrThrow().mutableMethod.apply {
|
||||
listOf(
|
||||
ytOutlinePictureInPictureWhite24 to ytOutlineXWhite24,
|
||||
ytOutlineXWhite24 to ytOutlinePictureInPictureWhite24,
|
||||
).forEach { (originalResource, replacementResource) ->
|
||||
val imageResourceIndex = indexOfFirstWideLiteralInstructionValueOrThrow(originalResource)
|
||||
val register = getInstruction<OneRegisterInstruction>(imageResourceIndex).registerA
|
||||
|
||||
replaceInstruction(imageResourceIndex, "const v$register, $replacementResource")
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
|
||||
// region Add hooks to hide tablet modern miniplayer buttons.
|
||||
|
||||
listOf(
|
||||
Triple(MiniplayerModernExpandButtonFingerprint, modernMiniplayerExpand,"hideMiniplayerExpandClose"),
|
||||
Triple(MiniplayerModernCloseButtonFingerprint, modernMiniplayerClose, "hideMiniplayerExpandClose"),
|
||||
Triple(MiniplayerModernRewindButtonFingerprint, modernMiniplayerRewindButton, "hideMiniplayerRewindForward"),
|
||||
Triple(MiniplayerModernForwardButtonFingerprint, modernMiniplayerForwardButton, "hideMiniplayerRewindForward"),
|
||||
Triple(MiniplayerModernOverlayViewFingerprint, scrimOverlay, "adjustMiniplayerOpacity")
|
||||
).forEach { (fingerprint, literalValue, methodName) ->
|
||||
fingerprint.resolve(
|
||||
context,
|
||||
MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
|
||||
fingerprint.hookInflatedView(
|
||||
literalValue,
|
||||
"Landroid/widget/ImageView;",
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
|
||||
)
|
||||
}
|
||||
|
||||
MiniplayerModernAddViewListenerFingerprint.apply {
|
||||
resolve(
|
||||
context,
|
||||
MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
}.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->" +
|
||||
"hideMiniplayerSubTexts(Landroid/view/View;)V"
|
||||
)
|
||||
|
||||
|
||||
// Modern 2 has a broken overlay subtitle view that is always present.
|
||||
// Modern 2 uses the same overlay controls as the regular video player,
|
||||
// and the overlay views are added at runtime.
|
||||
// Add a hook to the overlay class, and pass the added views to integrations.
|
||||
YouTubePlayerOverlaysLayoutFingerprint.resultOrThrow().mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
|
||||
"addView",
|
||||
listOf(
|
||||
ImmutableMethodParameter("Landroid/view/View;", null, null),
|
||||
ImmutableMethodParameter("I", null, null),
|
||||
ImmutableMethodParameter("Landroid/view/ViewGroup\$LayoutParams;", null, null),
|
||||
),
|
||||
"V",
|
||||
AccessFlags.PUBLIC.value,
|
||||
null,
|
||||
null,
|
||||
MutableMethodImplementation(4),
|
||||
).toMutable().apply {
|
||||
addInstructions(
|
||||
"""
|
||||
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
|
||||
invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
|
||||
return-void
|
||||
""",
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
private fun Method.findReturnIndicesReversed() = findOpcodeIndicesReversed(Opcode.RETURN)
|
||||
|
||||
/**
|
||||
* Adds an override to force legacy tablet miniplayer to be used or not used.
|
||||
*/
|
||||
private fun MutableMethod.insertLegacyTabletMiniplayerOverride(index: Int) {
|
||||
insertBooleanOverride(index, "getLegacyTabletMiniplayerOverride")
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an override to force modern miniplayer to be used or not used.
|
||||
*/
|
||||
private fun MutableMethod.insertModernMiniplayerOverride(index: Int) {
|
||||
insertBooleanOverride(index, "getModernMiniplayerOverride")
|
||||
}
|
||||
|
||||
private fun MutableMethod.insertBooleanOverride(index: Int, methodName: String) {
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
addInstructions(
|
||||
index,
|
||||
"""
|
||||
invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Z)Z
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an override to specify which modern miniplayer is used.
|
||||
*/
|
||||
private fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
|
||||
val targetInstruction = getInstruction<TwoRegisterInstruction>(iPutIndex)
|
||||
val targetReference = (targetInstruction as ReferenceInstruction).reference
|
||||
|
||||
addInstructions(
|
||||
iPutIndex + 1, """
|
||||
invoke-static { v${targetInstruction.registerA} }, $INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
|
||||
move-result v${targetInstruction.registerA}
|
||||
# Original instruction
|
||||
iput v${targetInstruction.registerA}, v${targetInstruction.registerB}, $targetReference
|
||||
"""
|
||||
)
|
||||
removeInstruction(iPutIndex)
|
||||
}
|
||||
|
||||
private fun LiteralValueFingerprint.hookInflatedView(
|
||||
literalValue: Long,
|
||||
hookedClassType: String,
|
||||
integrationsMethodName: String,
|
||||
) {
|
||||
resultOrThrow().mutableMethod.apply {
|
||||
val imageViewIndex = indexOfFirstInstructionOrThrow(
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(literalValue)
|
||||
) {
|
||||
opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type == hookedClassType
|
||||
}
|
||||
|
||||
val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
|
||||
addInstruction(
|
||||
imageViewIndex + 1,
|
||||
"invoke-static { v$register }, $integrationsMethodName"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
|
||||
@Patch(dependencies = [ResourceMappingPatch::class])
|
||||
internal object MiniplayerResourcePatch : ResourcePatch() {
|
||||
var floatyBarButtonTopMargin = -1L
|
||||
|
||||
// Only available in 19.15 and upwards.
|
||||
var ytOutlineXWhite24 = -1L
|
||||
var ytOutlinePictureInPictureWhite24 = -1L
|
||||
var scrimOverlay = -1L
|
||||
var modernMiniplayerClose = -1L
|
||||
var modernMiniplayerExpand = -1L
|
||||
var modernMiniplayerRewindButton = -1L
|
||||
var modernMiniplayerForwardButton = -1L
|
||||
var playerOverlays = -1L
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
floatyBarButtonTopMargin = ResourceMappingPatch[
|
||||
"dimen",
|
||||
"floaty_bar_button_top_margin"
|
||||
]
|
||||
|
||||
try {
|
||||
ytOutlinePictureInPictureWhite24 = ResourceMappingPatch[
|
||||
"drawable",
|
||||
"yt_outline_picture_in_picture_white_24"
|
||||
]
|
||||
} catch (exception: PatchException) {
|
||||
// Ignore, and assume the app is 19.14 or earlier.
|
||||
return
|
||||
}
|
||||
|
||||
ytOutlineXWhite24 = ResourceMappingPatch[
|
||||
"drawable",
|
||||
"yt_outline_x_white_24"
|
||||
]
|
||||
|
||||
scrimOverlay = ResourceMappingPatch[
|
||||
"id",
|
||||
"scrim_overlay"
|
||||
]
|
||||
|
||||
modernMiniplayerClose = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_close"
|
||||
]
|
||||
|
||||
modernMiniplayerExpand = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_expand"
|
||||
]
|
||||
|
||||
modernMiniplayerRewindButton = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_rewind_button"
|
||||
]
|
||||
|
||||
modernMiniplayerForwardButton = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_forward_button"
|
||||
]
|
||||
|
||||
playerOverlays = ResourceMappingPatch[
|
||||
"layout",
|
||||
"player_overlays"
|
||||
]
|
||||
|
||||
// Resource id is not used during patching, but is used by integrations.
|
||||
// Verify the resource is present while patching.
|
||||
ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_subtitle_text"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniplayerDimensionsCalculatorParentFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("L"),
|
||||
literalSupplier = { MiniplayerResourcePatch.floatyBarButtonTopMargin }
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernAddViewListenerFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroid/view/View;")
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernCloseButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerClose }
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniplayerModernConstructorFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
parameters = listOf("L"),
|
||||
literalSupplier = { 45623000L } // Magic number found in the constructor.
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernExpandButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerExpand }
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernExpandCloseDrawablesFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("L"),
|
||||
literalSupplier = { MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24 }
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernForwardButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerForwardButton }
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernOverlayViewFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.scrimOverlay }
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernRewindButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerRewindButton }
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniplayerModernViewParentFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Ljava/lang/String;",
|
||||
parameters = listOf(),
|
||||
strings = listOf("player_overlay_modern_mini_player_controls")
|
||||
)
|
||||
@@ -1,10 +1,10 @@
|
||||
package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniPlayerOverrideFingerprint : MethodFingerprint(
|
||||
internal object MiniplayerOverrideFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
@@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.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 MiniplayerOverrideNoContextFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
returnType = "Z",
|
||||
opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
|
||||
)
|
||||
@@ -1,15 +1,15 @@
|
||||
package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
|
||||
package app.revanced.patches.youtube.layout.miniplayer.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 MiniPlayerResponseModelSizeCheckFingerprint : MethodFingerprint(
|
||||
"L",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||
listOf(
|
||||
internal object MiniplayerResponseModelSizeCheckFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "L",
|
||||
parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||
opcodes = listOf(
|
||||
Opcode.RETURN_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
||||
@@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||
|
||||
internal object YouTubePlayerOverlaysLayoutFingerprint : MethodFingerprint(
|
||||
customFingerprint = { _, classDef ->
|
||||
classDef.type == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||
}
|
||||
) {
|
||||
const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =
|
||||
"Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;"
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package app.revanced.patches.youtube.layout.player.overlay
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
@@ -9,6 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.youtube.layout.player.overlay.fingerprints.CreatePlayerOverviewFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
@@ -27,7 +27,7 @@ object CustomPlayerOverlayOpacityPatch : BytecodePatch(setOf(CreatePlayerOvervie
|
||||
CreatePlayerOverviewFingerprint.result?.let { result ->
|
||||
result.mutableMethod.apply {
|
||||
val viewRegisterIndex =
|
||||
indexOfFirstWideLiteralInstructionValue(CustomPlayerOverlayOpacityResourcePatch.scrimOverlayId) + 3
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(CustomPlayerOverlayOpacityResourcePatch.scrimOverlayId) + 3
|
||||
val viewRegister =
|
||||
getInstruction<OneRegisterInstruction>(viewRegisterIndex).registerA
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package app.revanced.patches.youtube.layout.seekbar
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
@@ -15,6 +13,8 @@ import app.revanced.patches.youtube.layout.seekbar.fingerprints.ShortsSeekbarCol
|
||||
import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch
|
||||
import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch.lithoColorOverrideHook
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
@@ -30,7 +30,7 @@ internal object SeekbarColorBytecodePatch : BytecodePatch(
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
fun MutableMethod.addColorChangeInstructions(resourceId: Long) {
|
||||
val registerIndex = indexOfFirstWideLiteralInstructionValue(resourceId) + 2
|
||||
val registerIndex = indexOfFirstWideLiteralInstructionValueOrThrow(resourceId) + 2
|
||||
val colorRegister = getInstruction<OneRegisterInstruction>(registerIndex).registerA
|
||||
addInstructions(
|
||||
registerIndex + 1,
|
||||
|
||||
@@ -13,18 +13,51 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
name = "Enable tablet layout",
|
||||
description = "Adds an option to spoof the device form factor to a tablet which enables the tablet layout.",
|
||||
dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.youtube")]
|
||||
description = "Adds an option to enable tablet layout",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube", arrayOf(
|
||||
"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 EnableTabletLayoutPatch : BytecodePatch(
|
||||
setOf(GetFormFactorFingerprint)
|
||||
) {
|
||||
object EnableTabletLayoutPatch : BytecodePatch(setOf(GetFormFactorFingerprint)) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/TabletLayoutPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
@@ -32,7 +65,7 @@ object EnableTabletLayoutPatch : BytecodePatch(
|
||||
SwitchPreference("revanced_tablet_layout")
|
||||
)
|
||||
|
||||
GetFormFactorFingerprint.result?.let {
|
||||
GetFormFactorFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val returnIsLargeFormFactorIndex = getInstructions().lastIndex - 4
|
||||
val returnIsLargeFormFactorLabel = getInstruction(returnIsLargeFormFactorIndex)
|
||||
@@ -40,8 +73,8 @@ object EnableTabletLayoutPatch : BytecodePatch(
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, Lapp/revanced/integrations/youtube/patches/EnableTabletLayoutPatch;->enableTabletLayout()Z
|
||||
move-result v0 # Free register
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getTabletLayoutEnabled()Z
|
||||
move-result v0
|
||||
if-nez v0, :is_large_form_factor
|
||||
""",
|
||||
ExternalLabel(
|
||||
@@ -50,6 +83,6 @@ object EnableTabletLayoutPatch : BytecodePatch(
|
||||
)
|
||||
)
|
||||
}
|
||||
} ?: GetFormFactorFingerprint.exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,6 @@ internal object GetFormFactorFingerprint : MethodFingerprint(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.RETURN_OBJECT
|
||||
)
|
||||
),
|
||||
strings = listOf("")
|
||||
)
|
||||
@@ -1,152 +1,11 @@
|
||||
package app.revanced.patches.youtube.layout.tabletminiplayer
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerDimensionsCalculatorParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideFingerprint
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideNoContextFingerprint
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerPatch
|
||||
|
||||
@Patch(
|
||||
name = "Tablet mini player",
|
||||
description = "Adds an option to enable the tablet mini player layout.",
|
||||
dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube", arrayOf(
|
||||
"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 TabletMiniPlayerPatch : BytecodePatch(
|
||||
setOf(
|
||||
MiniPlayerDimensionsCalculatorParentFingerprint,
|
||||
MiniPlayerResponseModelSizeCheckFingerprint,
|
||||
MiniPlayerOverrideFingerprint
|
||||
)
|
||||
) {
|
||||
@Deprecated("This patch class has been renamed to Miniplayer.")
|
||||
object TabletMiniPlayerPatch : BytecodePatch(dependencies = setOf(MiniplayerPatch::class)) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
SwitchPreference("revanced_tablet_miniplayer")
|
||||
)
|
||||
|
||||
// First resolve the fingerprints via the parent fingerprint.
|
||||
MiniPlayerDimensionsCalculatorParentFingerprint.result
|
||||
?: throw MiniPlayerDimensionsCalculatorParentFingerprint.exception
|
||||
val miniPlayerClass = MiniPlayerDimensionsCalculatorParentFingerprint.result!!.classDef
|
||||
|
||||
/*
|
||||
* No context parameter method.
|
||||
*/
|
||||
MiniPlayerOverrideNoContextFingerprint.resolve(context, miniPlayerClass)
|
||||
val (method, _, parameterRegister) = MiniPlayerOverrideNoContextFingerprint.addProxyCall()
|
||||
|
||||
// Insert right before the return instruction.
|
||||
val secondInsertIndex = method.implementation!!.instructions.size - 1
|
||||
method.insertOverride(
|
||||
secondInsertIndex, parameterRegister
|
||||
/** same register used to return **/
|
||||
)
|
||||
|
||||
/*
|
||||
* Override every return instruction with the proxy call.
|
||||
*/
|
||||
MiniPlayerOverrideFingerprint.result?.let { result ->
|
||||
result.mutableMethod.let { method ->
|
||||
val appNameStringIndex = result.scanResult.stringsScanResult!!.matches.first().index + 2
|
||||
context.toMethodWalker(method).nextMethod(appNameStringIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
}.apply {
|
||||
implementation!!.let { implementation ->
|
||||
val returnIndices = implementation.instructions
|
||||
.withIndex()
|
||||
.filter { (_, instruction) -> instruction.opcode == Opcode.RETURN }
|
||||
.map { (index, _) -> index }
|
||||
|
||||
if (returnIndices.isEmpty()) throw PatchException("No return instructions found.")
|
||||
|
||||
// This method clobbers register p0 to return the value, calculate to override.
|
||||
val returnedRegister = implementation.registerCount - parameters.size
|
||||
|
||||
// Hook the returned register on every return instruction.
|
||||
returnIndices.forEach { index -> insertOverride(index, returnedRegister) }
|
||||
}
|
||||
}
|
||||
|
||||
return@let
|
||||
} ?: throw MiniPlayerOverrideFingerprint.exception
|
||||
|
||||
/*
|
||||
* Size check return value override.
|
||||
*/
|
||||
MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall()
|
||||
}
|
||||
|
||||
// Helper methods.
|
||||
private fun MethodFingerprint.addProxyCall(): Triple<MutableMethod, Int, Int> {
|
||||
val (method, scanIndex, parameterRegister) = this.unwrap()
|
||||
method.insertOverride(scanIndex, parameterRegister)
|
||||
|
||||
return Triple(method, scanIndex, parameterRegister)
|
||||
}
|
||||
|
||||
private fun MutableMethod.insertOverride(index: Int, overrideRegister: Int) {
|
||||
this.addInstructions(
|
||||
index,
|
||||
"""
|
||||
invoke-static {v$overrideRegister}, Lapp/revanced/integrations/youtube/patches/TabletMiniPlayerOverridePatch;->getTabletMiniPlayerOverride(Z)Z
|
||||
move-result v$overrideRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
private fun MethodFingerprint.unwrap(): Triple<MutableMethod, Int, Int> {
|
||||
val result = this.result!!
|
||||
val scanIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
val method = result.mutableMethod
|
||||
val instructions = method.implementation!!.instructions
|
||||
val parameterRegister = (instructions[scanIndex] as OneRegisterInstruction).registerA
|
||||
|
||||
return Triple(method, scanIndex, parameterRegister)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.tabletminiplayer.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 MiniPlayerDimensionsCalculatorParentFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("F"),
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_HIGH16,
|
||||
Opcode.ADD_FLOAT_2ADDR,
|
||||
null, // Opcode.MUL_FLOAT or Opcode.MUL_FLOAT_2ADDR
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.FLOAT_TO_INT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.RETURN_VOID,
|
||||
)
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
package app.revanced.patches.youtube.layout.tabletminiplayer.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 MiniPlayerOverrideNoContextFingerprint : MethodFingerprint(
|
||||
"Z", AccessFlags.FINAL or AccessFlags.PRIVATE,
|
||||
opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction
|
||||
)
|
||||
@@ -16,7 +16,7 @@ import app.revanced.patches.youtube.layout.theme.fingerprints.UseGradientLoading
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@@ -123,7 +123,7 @@ object ThemeBytecodePatch : BytecodePatch(
|
||||
)
|
||||
|
||||
UseGradientLoadingScreenFingerprint.result?.mutableMethod?.apply {
|
||||
val isEnabledIndex = indexOfFirstWideLiteralInstructionValue(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3
|
||||
val isEnabledIndex = indexOfFirstWideLiteralInstructionValueOrThrow(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3
|
||||
val isEnabledRegister = getInstruction<OneRegisterInstruction>(isEnabledIndex - 1).registerA
|
||||
|
||||
addInstructions(
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
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
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Patch(
|
||||
name = "Remove background playback restrictions",
|
||||
description = "Removes restrictions on background playback, including playing kids videos in the background.",
|
||||
dependencies = [
|
||||
BackgroundPlaybackResourcePatch::class,
|
||||
IntegrationsPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
SettingsPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"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 BackgroundPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
BackgroundPlaybackManagerFingerprint,
|
||||
BackgroundPlaybackSettingsFingerprint,
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/BackgroundPlaybackPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
BackgroundPlaybackManagerFingerprint.resultOrThrow().mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackIsNotShort()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
|
||||
// Enable background playback option in YouTube settings
|
||||
BackgroundPlaybackSettingsFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val booleanCalls = implementation!!.instructions.withIndex()
|
||||
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }
|
||||
|
||||
val settingsBooleanIndex = booleanCalls.elementAt(1).index
|
||||
val settingsBooleanMethod =
|
||||
context.toMethodWalker(this).nextMethod(settingsBooleanIndex, true).getMethod() as MutableMethod
|
||||
|
||||
settingsBooleanMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideBackgroundPlaybackAvailable()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// Force allowing background play for videos labeled for kids.
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"return-void"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.misc.minimizedplayback
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
@@ -8,7 +8,7 @@ import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
@Patch(
|
||||
dependencies = [ResourceMappingPatch::class],
|
||||
)
|
||||
internal object MinimizedPlaybackResourcePatch : ResourcePatch() {
|
||||
internal object BackgroundPlaybackResourcePatch : ResourcePatch() {
|
||||
internal var prefBackgroundAndOfflineCategoryId: Long = -1
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
@@ -1,11 +1,11 @@
|
||||
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback.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 MinimizedPlaybackManagerFingerprint : MethodFingerprint(
|
||||
internal object BackgroundPlaybackManagerFingerprint : MethodFingerprint(
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
listOf("L"),
|
||||
@@ -1,12 +1,12 @@
|
||||
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.MinimizedPlaybackResourcePatch
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
|
||||
internal object BackgroundPlaybackSettingsFingerprint : LiteralValueFingerprint(
|
||||
returnType = "Ljava/lang/String;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf(),
|
||||
@@ -19,5 +19,5 @@ internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.GOTO
|
||||
),
|
||||
literalSupplier = { MinimizedPlaybackResourcePatch.prefBackgroundAndOfflineCategoryId }
|
||||
literalSupplier = { BackgroundPlaybackResourcePatch.prefBackgroundAndOfflineCategoryId }
|
||||
)
|
||||
@@ -1,12 +1,11 @@
|
||||
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||
|
||||
internal object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
internal object KidsBackgroundPlaybackPolicyControllerFingerprint : LiteralValueFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("I", "L", "L"),
|
||||
@@ -26,9 +25,5 @@ internal object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerp
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.implementation!!.instructions.any {
|
||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 5)
|
||||
}
|
||||
}
|
||||
literalSupplier = { 5 },
|
||||
)
|
||||
@@ -14,14 +14,8 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildInitPlaybackRequestFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildPlayerRequestURIFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerGestureConfigSyntheticFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SetPlayerRequestClientTypeFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
@@ -86,6 +80,9 @@ object SpoofClientPatch : BytecodePatch(
|
||||
|
||||
// Player gesture config.
|
||||
PlayerGestureConfigSyntheticFingerprint,
|
||||
|
||||
// Player speed menu item.
|
||||
CreatePlaybackSpeedMenuItemFingerprint,
|
||||
),
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
@@ -99,7 +96,7 @@ object SpoofClientPatch : BytecodePatch(
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
PreferenceScreen(
|
||||
key = "revanced_spoof_client_screen",
|
||||
sorting = Sorting.UNSORTED,
|
||||
sorting = PreferenceScreen.Sorting.UNSORTED,
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_spoof_client"),
|
||||
SwitchPreference("revanced_spoof_client_use_ios"),
|
||||
@@ -127,33 +124,6 @@ object SpoofClientPatch : BytecodePatch(
|
||||
|
||||
// endregion
|
||||
|
||||
// region fix player gesture.
|
||||
|
||||
PlayerGestureConfigSyntheticFingerprint.resultOrThrow().let {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
arrayOf(3, 9).forEach { offSet ->
|
||||
(context.toMethodWalker(it.mutableMethod)
|
||||
.nextMethod(endIndex - offSet, true)
|
||||
.getMethod() as MutableMethod)
|
||||
.apply {
|
||||
|
||||
val index = implementation!!.instructions.lastIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
|
||||
addInstructions(
|
||||
index,
|
||||
"""
|
||||
invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->enablePlayerGesture(Z)Z
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Block /get_watch requests to fall back to /player requests.
|
||||
|
||||
BuildPlayerRequestURIFingerprint.resultOrThrow().let {
|
||||
@@ -281,5 +251,59 @@ object SpoofClientPatch : BytecodePatch(
|
||||
|
||||
// endregion
|
||||
|
||||
// region Fix player gesture if spoofing to iOS.
|
||||
|
||||
PlayerGestureConfigSyntheticFingerprint.resultOrThrow().let {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val downAndOutLandscapeAllowedIndex = endIndex - 3
|
||||
val downAndOutPortraitAllowedIndex = endIndex - 9
|
||||
|
||||
arrayOf(
|
||||
downAndOutLandscapeAllowedIndex,
|
||||
downAndOutPortraitAllowedIndex,
|
||||
).forEach { index ->
|
||||
val gestureAllowedMethod = context.toMethodWalker(it.mutableMethod)
|
||||
.nextMethod(index, true)
|
||||
.getMethod() as MutableMethod
|
||||
|
||||
gestureAllowedMethod.apply {
|
||||
val isAllowedIndex = getInstructions().lastIndex
|
||||
val isAllowed = getInstruction<OneRegisterInstruction>(isAllowedIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
isAllowedIndex,
|
||||
"""
|
||||
invoke-static { v$isAllowed }, $INTEGRATIONS_CLASS_DESCRIPTOR->enablePlayerGesture(Z)Z
|
||||
move-result v$isAllowed
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// Fix playback speed menu item if spoofing to iOS.
|
||||
|
||||
CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let {
|
||||
val scanResult = it.scanResult.patternScanResult!!
|
||||
if (scanResult.startIndex != 0) throw PatchException("Unexpected start index: ${scanResult.startIndex}")
|
||||
|
||||
it.mutableMethod.apply {
|
||||
// Find the conditional check if the playback speed menu item is not created.
|
||||
val shouldCreateMenuIndex = indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
|
||||
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
shouldCreateMenuIndex,
|
||||
"""
|
||||
invoke-static { v$shouldCreateMenuRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceCreatePlaybackSpeedMenu(Z)Z
|
||||
move-result v$shouldCreateMenuRegister
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,14 @@ import app.revanced.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
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.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
object UserAgentClientSpoofPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
||||
private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube"
|
||||
@@ -42,20 +45,31 @@ object UserAgentClientSpoofPatch : BaseTransformInstructionsPatch<Instruction35c
|
||||
as? OneRegisterInstruction ?: return
|
||||
).registerA
|
||||
|
||||
// IndexOutOfBoundsException is not possible here,
|
||||
// IndexOutOfBoundsException is possible here,
|
||||
// but no such occurrences are present in the app.
|
||||
val referee = getInstruction(instructionIndex + 2).getReference<MethodReference>()?.toString()
|
||||
|
||||
// This can technically also match non-user agent string builder append methods,
|
||||
// but no such occurrences are present in the app.
|
||||
// Only replace string builder usage.
|
||||
if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) {
|
||||
return
|
||||
}
|
||||
|
||||
// Do not change the package name in methods that use resources, or for methods that use GmsCore.
|
||||
// Changing these package names will result in playback limitations,
|
||||
// particularly Android VR background audio only playback.
|
||||
val resourceOrGmsStringInstructionIndex = indexOfFirstInstruction {
|
||||
val reference = getReference<StringReference>()
|
||||
opcode == Opcode.CONST_STRING &&
|
||||
(reference?.string == "android.resource://" || reference?.string == "gcore_")
|
||||
}
|
||||
if (resourceOrGmsStringInstructionIndex >= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Overwrite the result of context.getPackageName() with the original package name.
|
||||
replaceInstruction(
|
||||
instructionIndex + 1,
|
||||
"const-string v$targetRegister, \"${ORIGINAL_PACKAGE_NAME}\"",
|
||||
"const-string v$targetRegister, \"$ORIGINAL_PACKAGE_NAME\"",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object CreatePlaybackSpeedMenuItemFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT, // First instruction of the method
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
null // MOVE_RESULT or MOVE_RESULT_OBJECT, Return value controls the creation of the playback speed menu item.
|
||||
),
|
||||
// 19.01 and earlier is missing the second parameter.
|
||||
// Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures.
|
||||
customFingerprint = custom@{ methodDef, _ ->
|
||||
// 19.01 and earlier parameters are: "[L"
|
||||
// 19.02+ parameters are "[L", "F"
|
||||
val parameterTypes = methodDef.parameterTypes
|
||||
val firstParameter = parameterTypes.firstOrNull()
|
||||
|
||||
if (firstParameter == null || !firstParameter.startsWith("[L")) {
|
||||
return@custom false
|
||||
}
|
||||
|
||||
parameterTypes.size == 1 || (parameterTypes.size == 2 && parameterTypes[1] == "F")
|
||||
}
|
||||
)
|
||||
@@ -1,9 +1,7 @@
|
||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerGestureConfigSyntheticFingerprint.indexOfDownAndOutAllowedInstruction
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
@@ -24,28 +22,28 @@ internal object PlayerGestureConfigSyntheticFingerprint : MethodFingerprint(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutLandscapeAllowed
|
||||
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutLandscapeAllowed.
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutPortraitAllowed
|
||||
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutPortraitAllowed.
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.RETURN_VOID,
|
||||
),
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
// This method is always called "a" because this kind of class always has a single method.
|
||||
methodDef.name == "a" && classDef.methods.count() == 2 &&
|
||||
indexOfDownAndOutAllowedInstruction(methodDef) >= 0
|
||||
}
|
||||
) {
|
||||
fun indexOfDownAndOutAllowedInstruction(methodDef: Method) =
|
||||
methodDef.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" &&
|
||||
fun indexOfDownAndOutAllowedInstruction(methodDef: Method) =
|
||||
methodDef.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" &&
|
||||
reference.parameterTypes.isEmpty() &&
|
||||
reference.returnType == "Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is always called "a" because this kind of class always has a single method.
|
||||
methodDef.name == "a" && classDef.methods.count() == 2 &&
|
||||
indexOfDownAndOutAllowedInstruction(methodDef) >= 0
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,117 +1,11 @@
|
||||
package app.revanced.patches.youtube.misc.minimizedplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.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.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
|
||||
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Patch(
|
||||
name = "Minimized playback",
|
||||
description = "Unlocks options for picture-in-picture and background playback.",
|
||||
dependencies = [
|
||||
MinimizedPlaybackResourcePatch::class,
|
||||
IntegrationsPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"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 MinimizedPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
MinimizedPlaybackManagerFingerprint,
|
||||
MinimizedPlaybackSettingsFingerprint,
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/MinimizedPlaybackPatch;"
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackPatch
|
||||
|
||||
@Deprecated("This patch class has been renamed to BackgroundPlaybackPatch.")
|
||||
object MinimizedPlaybackPatch : BytecodePatch(dependencies = setOf(BackgroundPlaybackPatch::class)) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
NonInteractivePreference("revanced_minimized_playback")
|
||||
)
|
||||
|
||||
MinimizedPlaybackManagerFingerprint.result?.apply {
|
||||
mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackIsNotShort()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
} ?: throw MinimizedPlaybackManagerFingerprint.exception
|
||||
|
||||
// Enable minimized playback option in YouTube settings
|
||||
MinimizedPlaybackSettingsFingerprint.result?.apply {
|
||||
val booleanCalls = method.implementation!!.instructions.withIndex()
|
||||
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }
|
||||
|
||||
val settingsBooleanIndex = booleanCalls.elementAt(1).index
|
||||
val settingsBooleanMethod =
|
||||
context.toMethodWalker(method).nextMethod(settingsBooleanIndex, true).getMethod() as MutableMethod
|
||||
|
||||
settingsBooleanMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideMinimizedPlaybackAvailable()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
} ?: throw MinimizedPlaybackSettingsFingerprint.exception
|
||||
|
||||
// Force allowing background play for videos labeled for kids.
|
||||
// Some regions and YouTube accounts do not require this patch.
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint.result?.apply {
|
||||
mutableMethod.addInstruction(
|
||||
0,
|
||||
"return-void"
|
||||
)
|
||||
} ?: throw KidsMinimizedPlaybackPolicyControllerFingerprint.exception
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ")
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
)
|
||||
@@ -4,13 +4,19 @@ 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.youtube.video.speed.button.PlaybackSpeedButtonPatch
|
||||
import app.revanced.patches.youtube.video.speed.custom.CustomPlaybackSpeedPatch
|
||||
import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPatch
|
||||
|
||||
@Patch(
|
||||
name = "Playback speed",
|
||||
description = "Adds options to customize available playback speeds and to remember the last playback speed selected.",
|
||||
dependencies = [CustomPlaybackSpeedPatch::class, RememberPlaybackSpeedPatch::class],
|
||||
description = "Adds options to customize available playback speeds, remember the last playback speed selected " +
|
||||
"and show a speed dialog button to the video player.",
|
||||
dependencies = [
|
||||
PlaybackSpeedButtonPatch::class,
|
||||
CustomPlaybackSpeedPatch::class,
|
||||
RememberPlaybackSpeedPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
@@ -42,4 +48,4 @@ object PlaybackSpeedPatch : BytecodePatch(emptySet()) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
// All patches this patch depends on succeed.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package app.revanced.patches.youtube.video.speed.button
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
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.playercontrols.PlayerControlsBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.speed.custom.CustomPlaybackSpeedPatch
|
||||
|
||||
@Patch(
|
||||
description = "Adds the option to display playback speed dialog button in the video player.",
|
||||
dependencies = [
|
||||
PlaybackSpeedButtonResourcePatch::class,
|
||||
CustomPlaybackSpeedPatch::class,
|
||||
PlayerControlsBytecodePatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object PlaybackSpeedButtonPatch : BytecodePatch(emptySet()) {
|
||||
private const val SPEED_BUTTON_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/videoplayer/PlaybackSpeedDialogButton;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||
SwitchPreference("revanced_playback_speed_dialog_button"),
|
||||
)
|
||||
|
||||
PlayerControlsBytecodePatch.initializeControl("$SPEED_BUTTON_CLASS_DESCRIPTOR->initializeButton(Landroid/view/View;)V")
|
||||
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$SPEED_BUTTON_CLASS_DESCRIPTOR->changeVisibility(Z)V")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package app.revanced.patches.youtube.video.speed.button
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
|
||||
import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.copyResources
|
||||
|
||||
@Patch(
|
||||
dependencies = [BottomControlsResourcePatch::class],
|
||||
)
|
||||
internal object PlaybackSpeedButtonResourcePatch : ResourcePatch() {
|
||||
override fun execute(context: ResourceContext) {
|
||||
context.copyResources(
|
||||
"speedbutton",
|
||||
ResourceGroup(
|
||||
"drawable",
|
||||
"revanced_playback_speed_dialog_button.xml",
|
||||
),
|
||||
)
|
||||
|
||||
BottomControlsResourcePatch.addControls("speedbutton")
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
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.ReferenceInstruction
|
||||
@@ -99,6 +100,7 @@ fun Method.indexOfIdResourceOrThrow(resourceName: String): Int {
|
||||
* Find the index of the first wide literal instruction with the given value.
|
||||
*
|
||||
* @return the first literal instruction with the value, or -1 if not found.
|
||||
* @see indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
*/
|
||||
fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementation?.let {
|
||||
it.instructions.indexOfFirst { instruction ->
|
||||
@@ -106,6 +108,18 @@ fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementati
|
||||
}
|
||||
} ?: -1
|
||||
|
||||
/**
|
||||
* Find the index of the first wide literal instruction with the given value,
|
||||
* or throw an exception if not found.
|
||||
*
|
||||
* @return the first literal instruction with the value, or throws [PatchException] if not found.
|
||||
*/
|
||||
fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long) : Int {
|
||||
val index = indexOfFirstWideLiteralInstructionValue(literal)
|
||||
if (index < 0) throw PatchException("Could not find literal value: $literal")
|
||||
return index
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the method contains a literal with the given value.
|
||||
*
|
||||
@@ -144,7 +158,9 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
|
||||
* @return The index of the first [Instruction] that matches the predicate.
|
||||
*/
|
||||
// TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
|
||||
@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
|
||||
// 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)"))
|
||||
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
|
||||
|
||||
/**
|
||||
@@ -179,6 +195,21 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instru
|
||||
return index
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The list of indices of the opcode in reverse order.
|
||||
*/
|
||||
fun Method.findOpcodeIndicesReversed(opcode: Opcode): List<Int> {
|
||||
val indexes = implementation!!.instructions
|
||||
.withIndex()
|
||||
.filter { (_, instruction) -> instruction.opcode == opcode }
|
||||
.map { (index, _) -> index }
|
||||
.reversed()
|
||||
|
||||
if (indexes.isEmpty()) throw PatchException("No ${opcode.name} instructions found in: $this")
|
||||
|
||||
return indexes
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved methods of [MethodFingerprint]s early.
|
||||
*/
|
||||
|
||||
263
src/main/resources/addresources/values-af-rZA/strings.xml
Normal file
263
src/main/resources/addresources/values-af-rZA/strings.xml
Normal 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.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.backgroundplayback.BackgroundPlaybackPatch">
|
||||
</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>
|
||||
263
src/main/resources/addresources/values-am-rET/strings.xml
Normal file
263
src/main/resources/addresources/values-am-rET/strings.xml
Normal 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.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.backgroundplayback.BackgroundPlaybackPatch">
|
||||
</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>
|
||||
1185
src/main/resources/addresources/values-ar-rSA/strings.xml
Normal file
1185
src/main/resources/addresources/values-ar-rSA/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
263
src/main/resources/addresources/values-as-rIN/strings.xml
Normal file
263
src/main/resources/addresources/values-as-rIN/strings.xml
Normal 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.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.backgroundplayback.BackgroundPlaybackPatch">
|
||||
</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>
|
||||
1185
src/main/resources/addresources/values-az-rAZ/strings.xml
Normal file
1185
src/main/resources/addresources/values-az-rAZ/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
1184
src/main/resources/addresources/values-be-rBY/strings.xml
Normal file
1184
src/main/resources/addresources/values-be-rBY/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
537
src/main/resources/addresources/values-bg-rBG/strings.xml
Normal file
537
src/main/resources/addresources/values-bg-rBG/strings.xml
Normal 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.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.backgroundplayback.BackgroundPlaybackPatch">
|
||||
</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>
|
||||
1115
src/main/resources/addresources/values-bn-rBD/strings.xml
Normal file
1115
src/main/resources/addresources/values-bn-rBD/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
263
src/main/resources/addresources/values-bs-rBA/strings.xml
Normal file
263
src/main/resources/addresources/values-bs-rBA/strings.xml
Normal 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.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.backgroundplayback.BackgroundPlaybackPatch">
|
||||
</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>
|
||||
272
src/main/resources/addresources/values-ca-rES/strings.xml
Normal file
272
src/main/resources/addresources/values-ca-rES/strings.xml
Normal 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.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.backgroundplayback.BackgroundPlaybackPatch">
|
||||
</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>
|
||||
1206
src/main/resources/addresources/values-cs-rCZ/strings.xml
Normal file
1206
src/main/resources/addresources/values-cs-rCZ/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
1203
src/main/resources/addresources/values-da-rDK/strings.xml
Normal file
1203
src/main/resources/addresources/values-da-rDK/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
1203
src/main/resources/addresources/values-de-rDE/strings.xml
Normal file
1203
src/main/resources/addresources/values-de-rDE/strings.xml
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user