mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-08 18:33:57 +01:00
Compare commits
122 Commits
v5.42.0-de
...
v5.45.0-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12e7c0943a | ||
|
|
a0c5604951 | ||
|
|
38d9299dfe | ||
|
|
dfdbbfa047 | ||
|
|
e9f45ce926 | ||
|
|
1b38b1a3c8 | ||
|
|
13cf1724bf | ||
|
|
6d01863ec7 | ||
|
|
a32ed30b4c | ||
|
|
ef44eaa119 | ||
|
|
c73a03c9e1 | ||
|
|
c1681f982a | ||
|
|
1502bf7524 | ||
|
|
dffb1e6525 | ||
|
|
b8c2ede2bf | ||
|
|
591e106098 | ||
|
|
e7336d2ef3 | ||
|
|
7a53f8f62d | ||
|
|
3466d9d210 | ||
|
|
876d7a6b03 | ||
|
|
a2aa9cac27 | ||
|
|
08baa19b4a | ||
|
|
7283b93cea | ||
|
|
754b71959a | ||
|
|
c64e29ec57 | ||
|
|
b2dd008aee | ||
|
|
de97562c5d | ||
|
|
6373829fd6 | ||
|
|
cfd244b408 | ||
|
|
e8e28e2b6a | ||
|
|
2e4c6fdcad | ||
|
|
644d6dcb51 | ||
|
|
14dd7346a8 | ||
|
|
0af8c8a766 | ||
|
|
96454c843b | ||
|
|
476ef0fae1 | ||
|
|
bbec724afb | ||
|
|
7a1dcbd4ee | ||
|
|
2a1e31860f | ||
|
|
949d6bdd19 | ||
|
|
7563990750 | ||
|
|
4b605eb270 | ||
|
|
c2d7a7fb8b | ||
|
|
a55560dc25 | ||
|
|
e8522d703e | ||
|
|
068d029a03 | ||
|
|
0c19dbaf30 | ||
|
|
bf73ac8316 | ||
|
|
95eee59a87 | ||
|
|
566875ea53 | ||
|
|
10ea250d4a | ||
|
|
5bd0f11630 | ||
|
|
4547ecb73c | ||
|
|
50f0b9c5ee | ||
|
|
a8c4bdb8a6 | ||
|
|
6555f6e6f8 | ||
|
|
a0e2c5c7b9 | ||
|
|
54846253d7 | ||
|
|
a98e8f7370 | ||
|
|
2d928e0cd6 | ||
|
|
be2b144cc9 | ||
|
|
52c0bb6aa2 | ||
|
|
38a49cc2a1 | ||
|
|
91044b3a50 | ||
|
|
fd4b2e1bb9 | ||
|
|
d0f20c8c7f | ||
|
|
d65dbc749c | ||
|
|
143dcef2b8 | ||
|
|
dbfc5be464 | ||
|
|
0fe545cad6 | ||
|
|
feca17be68 | ||
|
|
7afeaebb5c | ||
|
|
60a581a632 | ||
|
|
104d096ada | ||
|
|
19dcbd8efb | ||
|
|
a50f3b5177 | ||
|
|
64d22a9c31 | ||
|
|
bd4ba2dae8 | ||
|
|
f51b260d1d | ||
|
|
63be54dd09 | ||
|
|
bb222d7a26 | ||
|
|
f03256c471 | ||
|
|
fe16433f20 | ||
|
|
2154d89242 | ||
|
|
277a8b6b47 | ||
|
|
20c413120b | ||
|
|
5ed092bb7d | ||
|
|
19949e1695 | ||
|
|
ec0acc0f13 | ||
|
|
a30a849e6e | ||
|
|
603025a122 | ||
|
|
9441e7acb4 | ||
|
|
963a4ef43f | ||
|
|
0acba30245 | ||
|
|
6b26346914 | ||
|
|
b1511c732d | ||
|
|
26117e744c | ||
|
|
a62ee43441 | ||
|
|
6a799110d7 | ||
|
|
aec17b93f7 | ||
|
|
e7a1706be4 | ||
|
|
9469604fe0 | ||
|
|
1a3a12df1a | ||
|
|
ae4b9474d3 | ||
|
|
83ccd9d3f1 | ||
|
|
526c7c05e2 | ||
|
|
d0d53d109e | ||
|
|
9d6731660b | ||
|
|
5a7e199162 | ||
|
|
0c662c8e3b | ||
|
|
08e8ead04f | ||
|
|
d238a42708 | ||
|
|
673609c2aa | ||
|
|
5f1a485e8f | ||
|
|
6961babee9 | ||
|
|
328c9b6bbe | ||
|
|
4c8b56f546 | ||
|
|
1754023dd6 | ||
|
|
328234f39a | ||
|
|
326953cfc3 | ||
|
|
725d5dc974 | ||
|
|
76b0364c5b |
4
.github/workflows/build_pull_request.yml
vendored
4
.github/workflows/build_pull_request.yml
vendored
@@ -12,10 +12,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|||||||
2
.github/workflows/open_pull_request.yml
vendored
2
.github/workflows/open_pull_request.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Open pull request
|
- name: Open pull request
|
||||||
uses: repo-sync/pull-request@v2
|
uses: repo-sync/pull-request@v2
|
||||||
|
|||||||
2
.github/workflows/pull_strings.yml
vendored
2
.github/workflows/pull_strings.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
clean: true
|
clean: true
|
||||||
|
|||||||
2
.github/workflows/push_strings.yml
vendored
2
.github/workflows/push_strings.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Preprocess strings
|
- name: Preprocess strings
|
||||||
env:
|
env:
|
||||||
|
|||||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -18,10 +18,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v5
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
run: ./gradlew :patches:buildAndroid clean
|
run: ./gradlew :patches:buildAndroid clean
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v5
|
||||||
with:
|
with:
|
||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
@@ -51,14 +51,14 @@ jobs:
|
|||||||
fingerprint: ${{ vars.GPG_FINGERPRINT }}
|
fingerprint: ${{ vars.GPG_FINGERPRINT }}
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: cycjimmy/semantic-release-action@v4
|
uses: cycjimmy/semantic-release-action@v5
|
||||||
id: release
|
id: release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Attest
|
- name: Attest
|
||||||
if: steps.release.outputs.new_release_published == 'true'
|
if: steps.release.outputs.new_release_published == 'true'
|
||||||
uses: actions/attest-build-provenance@v2
|
uses: actions/attest-build-provenance@v3
|
||||||
with:
|
with:
|
||||||
subject-name: 'ReVanced Patches ${{ steps.release.outputs.new_release_git_tag }}'
|
subject-name: 'ReVanced Patches ${{ steps.release.outputs.new_release_git_tag }}'
|
||||||
subject-path: patches/build/libs/patches-*.rvp
|
subject-path: patches/build/libs/patches-*.rvp
|
||||||
|
|||||||
2
.github/workflows/update-gradle-wrapper.yml
vendored
2
.github/workflows/update-gradle-wrapper.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Update Gradle Wrapper
|
- name: Update Gradle Wrapper
|
||||||
uses: gradle-update/update-gradle-wrapper-action@v1
|
uses: gradle-update/update-gradle-wrapper-action@v1
|
||||||
|
|||||||
399
CHANGELOG.md
399
CHANGELOG.md
@@ -1,3 +1,402 @@
|
|||||||
|
# [5.45.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.3...v5.45.0-dev.4) (2025-10-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Change header:** Do not mirror header graphic with RTL languages ([a0c5604](https://github.com/ReVanced/revanced-patches/commit/a0c56049510ce040e1ccd49257864672c343344d))
|
||||||
|
|
||||||
|
# [5.45.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.2...v5.45.0-dev.3) (2025-10-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - Change Header:** Use SVG for header logo ([#6178](https://github.com/ReVanced/revanced-patches/issues/6178)) ([e9f45ce](https://github.com/ReVanced/revanced-patches/commit/e9f45ce92695d5857473ff71c14b190bded28a73))
|
||||||
|
|
||||||
|
# [5.45.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.45.0-dev.1...v5.45.0-dev.2) (2025-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Force original audio:** Fall back to visionOS and not Android Studio if Android VR is not available ([6d01863](https://github.com/ReVanced/revanced-patches/commit/6d01863ec70617d9abc864ce6686ed9764dd151d))
|
||||||
|
* **YouTube Music - Hide category bar:** Correctly hide the category bar in newer app targets ([#6175](https://github.com/ReVanced/revanced-patches/issues/6175)) ([13cf172](https://github.com/ReVanced/revanced-patches/commit/13cf1724bf2f946c7129cab0db96721c90f9fe89))
|
||||||
|
|
||||||
|
# [5.45.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.44.0...v5.45.0-dev.1) (2025-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Instagram:** Update failing fingerprints on newer versions ([#6181](https://github.com/ReVanced/revanced-patches/issues/6181)) ([c73a03c](https://github.com/ReVanced/revanced-patches/commit/c73a03c9e18a12262939c974cdf16221221d1487))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **TikTok:** Add `Sanitize sharing links` patch ([#6176](https://github.com/ReVanced/revanced-patches/issues/6176)) ([ef44eaa](https://github.com/ReVanced/revanced-patches/commit/ef44eaa119b9d6c5faec051e22d20f883d0da4f1))
|
||||||
|
|
||||||
|
# [5.44.0](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.44.0) (2025-10-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
|
||||||
|
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
|
||||||
|
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
|
||||||
|
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
|
||||||
|
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
|
||||||
|
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
|
||||||
|
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
|
||||||
|
|
||||||
|
# [5.44.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.3...v5.44.0-dev.4) (2025-10-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Add `Custom network security` patch ([#6151](https://github.com/ReVanced/revanced-patches/issues/6151)) ([e7336d2](https://github.com/ReVanced/revanced-patches/commit/e7336d2ef361cc5d6fe6e8442b36d9cf1f542931))
|
||||||
|
* **Duolingo:** Add `Skip energy recharge ads` patch ([#6167](https://github.com/ReVanced/revanced-patches/issues/6167)) ([591e106](https://github.com/ReVanced/revanced-patches/commit/591e106098c6eff431b8b7ac7d985ce7373d701e))
|
||||||
|
|
||||||
|
# [5.44.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.2...v5.44.0-dev.3) (2025-10-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Duolingo - Enable debug menu:** Support latest app target ([#6163](https://github.com/ReVanced/revanced-patches/issues/6163)) ([08baa19](https://github.com/ReVanced/revanced-patches/commit/08baa19b4a62e62bd103d177c3f4454de199cf16))
|
||||||
|
|
||||||
|
# [5.44.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.44.0-dev.1...v5.44.0-dev.2) (2025-10-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Google Photos - Spoof features:** Add support for Pixel 10 devices ([#6161](https://github.com/ReVanced/revanced-patches/issues/6161)) ([754b719](https://github.com/ReVanced/revanced-patches/commit/754b71959a0155413eb33cf1bdc2c8976eaca634))
|
||||||
|
|
||||||
|
# [5.44.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.3...v5.44.0-dev.1) (2025-10-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Samsung Radio:** Add `Disable device checks` patch ([#6145](https://github.com/ReVanced/revanced-patches/issues/6145)) ([de97562](https://github.com/ReVanced/revanced-patches/commit/de97562c5ddc8ec707761c1e04e74c4e18f9c158))
|
||||||
|
|
||||||
|
## [5.43.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.2...v5.43.2-dev.3) (2025-10-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Hide layout components:** Hide new kind of community post ([#6146](https://github.com/ReVanced/revanced-patches/issues/6146)) ([cfd244b](https://github.com/ReVanced/revanced-patches/commit/cfd244b4088daacd2788ec38357ac521e4b296d5))
|
||||||
|
|
||||||
|
## [5.43.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.2-dev.1...v5.43.2-dev.2) (2025-10-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube Music:** Resolve patching 7.29 target ([2e4c6fd](https://github.com/ReVanced/revanced-patches/commit/2e4c6fdcadeef45a80733e374421d52e5e8af910))
|
||||||
|
|
||||||
|
## [5.43.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.1...v5.43.2-dev.1) (2025-10-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter - Change link sharing domain:** Use bytecode patching to resolve patching with Manager ([#6125](https://github.com/ReVanced/revanced-patches/issues/6125)) ([0af8c8a](https://github.com/ReVanced/revanced-patches/commit/0af8c8a766ae4ba6926404d59da2f14d649f91f7))
|
||||||
|
|
||||||
|
## [5.43.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1) (2025-10-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
|
||||||
|
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
|
||||||
|
|
||||||
|
## [5.43.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.1-dev.1...v5.43.1-dev.2) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter:** Do not crash Manager when clicking on domain patch option ([2a1e318](https://github.com/ReVanced/revanced-patches/commit/2a1e31860f22f537d51b40a5b71d9ad9d538789e))
|
||||||
|
|
||||||
|
## [5.43.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.43.0...v5.43.1-dev.1) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter - Change link sharing domain:** Resolve duplicate patch option ([#6119](https://github.com/ReVanced/revanced-patches/issues/6119)) ([7563990](https://github.com/ReVanced/revanced-patches/commit/75639907502382f63fa127a886362d4a4573e6e3))
|
||||||
|
|
||||||
|
# [5.43.0](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.43.0) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d))
|
||||||
|
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](https://github.com/ReVanced/revanced-patches/commit/be2b144cc9c4108ec37e16f3dd20573d88ffaa2b))
|
||||||
|
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](https://github.com/ReVanced/revanced-patches/commit/54846253d748f4e7e30b2bba427c7d2fb9c341e2))
|
||||||
|
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](https://github.com/ReVanced/revanced-patches/commit/6555f6e6f8b52c2f1ddab1f52c6704cd2d8cfc12))
|
||||||
|
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
|
||||||
|
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b))
|
||||||
|
|
||||||
|
# [5.43.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.3...v5.43.0-dev.4) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Force original audio:** Do not use translated audio if stream spoofing is off and force audio is on ([0c19dba](https://github.com/ReVanced/revanced-patches/commit/0c19dbaf30bcb95a29448d98b028ebeea54cc7d3))
|
||||||
|
|
||||||
|
# [5.43.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.2...v5.43.0-dev.3) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Custom branding:** Use white notification icon for expanded status bar panel ([95eee59](https://github.com/ReVanced/revanced-patches/commit/95eee59a87a680e212a3ba06e1afefee8d91ee9d))
|
||||||
|
|
||||||
|
# [5.43.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.43.0-dev.1...v5.43.0-dev.2) (2025-10-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Custom branding:** Use ReVanced icon for status bar notification icon ([#6108](https://github.com/ReVanced/revanced-patches/issues/6108)) ([10ea250](https://github.com/ReVanced/revanced-patches/commit/10ea250d4a91f8ab3b7f865612a403fc93a857b5))
|
||||||
|
|
||||||
|
# [5.43.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.3...v5.43.0-dev.1) (2025-10-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Instagram:** Add `Hide suggested content` patch ([#6075](https://github.com/ReVanced/revanced-patches/issues/6075)) ([50f0b9c](https://github.com/ReVanced/revanced-patches/commit/50f0b9c5eee95ff5f9974e344802e1d2a4aab47b))
|
||||||
|
|
||||||
|
## [5.42.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.2...v5.42.2-dev.3) (2025-10-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Custom branding:** Do not add a broken custom icon if the user provides an invalid custom icon path ([6555f6e](https://github.com/ReVanced/revanced-patches/commit/6555f6e6f8b52c2f1ddab1f52c6704cd2d8cfc12))
|
||||||
|
|
||||||
|
## [5.42.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.2-dev.1...v5.42.2-dev.2) (2025-10-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter - Change Link Sharing Domain:** Change link domain of share copy action ([#6091](https://github.com/ReVanced/revanced-patches/issues/6091)) ([5484625](https://github.com/ReVanced/revanced-patches/commit/54846253d748f4e7e30b2bba427c7d2fb9c341e2))
|
||||||
|
|
||||||
|
## [5.42.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.1...v5.42.2-dev.1) (2025-10-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Instagram - Change sharing domain:** Display patch option ([#6089](https://github.com/ReVanced/revanced-patches/issues/6089)) ([be2b144](https://github.com/ReVanced/revanced-patches/commit/be2b144cc9c4108ec37e16f3dd20573d88ffaa2b))
|
||||||
|
|
||||||
|
## [5.42.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1) (2025-10-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Custom Branding:** Resolve startup crash with root installation ([fd4b2e1](https://github.com/ReVanced/revanced-patches/commit/fd4b2e1bb98c6e507178e5b46b896ef7d320bc3d))
|
||||||
|
|
||||||
|
## [5.42.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.42.0...v5.42.1-dev.1) (2025-10-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Custom Branding:** Resolve startup crash with root installation ([fd4b2e1](https://github.com/ReVanced/revanced-patches/commit/fd4b2e1bb98c6e507178e5b46b896ef7d320bc3d))
|
||||||
|
|
||||||
|
# [5.42.0](https://github.com/ReVanced/revanced-patches/compare/v5.41.0...v5.42.0) (2025-10-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](https://github.com/ReVanced/revanced-patches/commit/9441e7acb4817e12d1443d438ef6c448518bd614))
|
||||||
|
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](https://github.com/ReVanced/revanced-patches/commit/ae4b9474d3fb62528fc21397c19954d31605e9da))
|
||||||
|
* **Instagram - Hide navigation buttons:** Resolve app startup crash ([080a226](https://github.com/ReVanced/revanced-patches/commit/080a2266146798be71789c939deef2f289697523))
|
||||||
|
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](https://github.com/ReVanced/revanced-patches/commit/19949e1695cc252ff0f94a33b6e3fb62e967d7fd))
|
||||||
|
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](https://github.com/ReVanced/revanced-patches/commit/673609c2aa87988cdc138eab101b9750fe6a7b62))
|
||||||
|
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](https://github.com/ReVanced/revanced-patches/commit/bd4ba2dae85ee6fd8d7e6078c3de775ca336e0b6))
|
||||||
|
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](https://github.com/ReVanced/revanced-patches/commit/9d6731660ba0e19b863d05d54aa04f74a879f69b))
|
||||||
|
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](https://github.com/ReVanced/revanced-patches/commit/76b0364c5b5562c6a0d178d2bbe5b220f48aaca9))
|
||||||
|
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](https://github.com/ReVanced/revanced-patches/commit/f03256c471e1ee6a12267c1b56b531ca8f89278c))
|
||||||
|
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](https://github.com/ReVanced/revanced-patches/commit/7afeaebb5cc22eb4f4512d8aa0cf4e835e7a2daf))
|
||||||
|
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](https://github.com/ReVanced/revanced-patches/commit/a62ee43441b197f5c8352ae373bb8919ad66f0bd))
|
||||||
|
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](https://github.com/ReVanced/revanced-patches/commit/328234f39ada81542e596f04e8ce410c787c15c8))
|
||||||
|
* **YouTube Music - Hide cast button:** Fix patching error ([28799a5](https://github.com/ReVanced/revanced-patches/commit/28799a548a73651134ef304cb6cb542cf8e55abe))
|
||||||
|
* **YouTube Music - Hide cast button:** Resolve button not hiding ([7817885](https://github.com/ReVanced/revanced-patches/commit/7817885cffed66608039ab45881537cbd3069c9d))
|
||||||
|
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](https://github.com/ReVanced/revanced-patches/commit/6b2634691423f5ce25a28b3f2fbc420977b81748))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](https://github.com/ReVanced/revanced-patches/commit/a50f3b5177808f07d84041c946caccb5a08ad387))
|
||||||
|
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](https://github.com/ReVanced/revanced-patches/commit/20c413120bad97af6121718e76b22a1b5540aa44))
|
||||||
|
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](https://github.com/ReVanced/revanced-patches/commit/2154d89242fd8d7f7460145d5d35a4f1986944a3))
|
||||||
|
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](https://github.com/ReVanced/revanced-patches/commit/08e8ead04ffff47a4608a3db7aadc8d5feccd4ad))
|
||||||
|
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](https://github.com/ReVanced/revanced-patches/commit/963a4ef43fd513de7a2d7d019992f06b62fdcc10))
|
||||||
|
* **Viber:** Add `Hide navigation buttons` patch ([#5991](https://github.com/ReVanced/revanced-patches/issues/5991)) ([5cb46c4](https://github.com/ReVanced/revanced-patches/commit/5cb46c4e9180ebc16eddb983dad73d137d8ec047))
|
||||||
|
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](https://github.com/ReVanced/revanced-patches/commit/4c8b56f5466b244737f501654eb7c5d34b6b2f88))
|
||||||
|
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](https://github.com/ReVanced/revanced-patches/commit/d0d53d109e451759a029326873adfa36fba12b23))
|
||||||
|
|
||||||
|
# [5.42.0](https://github.com/ReVanced/revanced-patches/compare/v5.41.0...v5.42.0) (2025-10-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](https://github.com/ReVanced/revanced-patches/commit/9441e7acb4817e12d1443d438ef6c448518bd614))
|
||||||
|
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](https://github.com/ReVanced/revanced-patches/commit/ae4b9474d3fb62528fc21397c19954d31605e9da))
|
||||||
|
* **Instagram - Hide navigation buttons:** Resolve app startup crash ([080a226](https://github.com/ReVanced/revanced-patches/commit/080a2266146798be71789c939deef2f289697523))
|
||||||
|
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](https://github.com/ReVanced/revanced-patches/commit/19949e1695cc252ff0f94a33b6e3fb62e967d7fd))
|
||||||
|
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](https://github.com/ReVanced/revanced-patches/commit/673609c2aa87988cdc138eab101b9750fe6a7b62))
|
||||||
|
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](https://github.com/ReVanced/revanced-patches/commit/bd4ba2dae85ee6fd8d7e6078c3de775ca336e0b6))
|
||||||
|
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](https://github.com/ReVanced/revanced-patches/commit/9d6731660ba0e19b863d05d54aa04f74a879f69b))
|
||||||
|
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](https://github.com/ReVanced/revanced-patches/commit/76b0364c5b5562c6a0d178d2bbe5b220f48aaca9))
|
||||||
|
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](https://github.com/ReVanced/revanced-patches/commit/f03256c471e1ee6a12267c1b56b531ca8f89278c))
|
||||||
|
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](https://github.com/ReVanced/revanced-patches/commit/7afeaebb5cc22eb4f4512d8aa0cf4e835e7a2daf))
|
||||||
|
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](https://github.com/ReVanced/revanced-patches/commit/a62ee43441b197f5c8352ae373bb8919ad66f0bd))
|
||||||
|
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](https://github.com/ReVanced/revanced-patches/commit/328234f39ada81542e596f04e8ce410c787c15c8))
|
||||||
|
* **YouTube Music - Hide cast button:** Fix patching error ([28799a5](https://github.com/ReVanced/revanced-patches/commit/28799a548a73651134ef304cb6cb542cf8e55abe))
|
||||||
|
* **YouTube Music - Hide cast button:** Resolve button not hiding ([7817885](https://github.com/ReVanced/revanced-patches/commit/7817885cffed66608039ab45881537cbd3069c9d))
|
||||||
|
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](https://github.com/ReVanced/revanced-patches/commit/6b2634691423f5ce25a28b3f2fbc420977b81748))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](https://github.com/ReVanced/revanced-patches/commit/a50f3b5177808f07d84041c946caccb5a08ad387))
|
||||||
|
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](https://github.com/ReVanced/revanced-patches/commit/20c413120bad97af6121718e76b22a1b5540aa44))
|
||||||
|
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](https://github.com/ReVanced/revanced-patches/commit/2154d89242fd8d7f7460145d5d35a4f1986944a3))
|
||||||
|
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](https://github.com/ReVanced/revanced-patches/commit/08e8ead04ffff47a4608a3db7aadc8d5feccd4ad))
|
||||||
|
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](https://github.com/ReVanced/revanced-patches/commit/963a4ef43fd513de7a2d7d019992f06b62fdcc10))
|
||||||
|
* **Viber:** Add `Hide navigation buttons` patch ([#5991](https://github.com/ReVanced/revanced-patches/issues/5991)) ([5cb46c4](https://github.com/ReVanced/revanced-patches/commit/5cb46c4e9180ebc16eddb983dad73d137d8ec047))
|
||||||
|
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](https://github.com/ReVanced/revanced-patches/commit/4c8b56f5466b244737f501654eb7c5d34b6b2f88))
|
||||||
|
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](https://github.com/ReVanced/revanced-patches/commit/d0d53d109e451759a029326873adfa36fba12b23))
|
||||||
|
|
||||||
|
# [5.42.0-dev.19](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.18...v5.42.0-dev.19) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof video streams:** Do not allow VR AV1 if "Force AVC" is enabled ([7afeaeb](https://github.com/ReVanced/revanced-patches/commit/7afeaebb5cc22eb4f4512d8aa0cf4e835e7a2daf))
|
||||||
|
|
||||||
|
# [5.42.0-dev.18](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.17...v5.42.0-dev.18) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Custom branding:** Add in-app settings to change icon and name ([#6059](https://github.com/ReVanced/revanced-patches/issues/6059)) ([a50f3b5](https://github.com/ReVanced/revanced-patches/commit/a50f3b5177808f07d84041c946caccb5a08ad387))
|
||||||
|
|
||||||
|
# [5.42.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.16...v5.42.0-dev.17) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Force original audio:** Change patch to default on ([#6070](https://github.com/ReVanced/revanced-patches/issues/6070)) ([bd4ba2d](https://github.com/ReVanced/revanced-patches/commit/bd4ba2dae85ee6fd8d7e6078c3de775ca336e0b6))
|
||||||
|
|
||||||
|
# [5.42.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.15...v5.42.0-dev.16) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof video streams:** Add "Allow Android VR AV1" setting ([#6071](https://github.com/ReVanced/revanced-patches/issues/6071)) ([f03256c](https://github.com/ReVanced/revanced-patches/commit/f03256c471e1ee6a12267c1b56b531ca8f89278c))
|
||||||
|
|
||||||
|
# [5.42.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.14...v5.42.0-dev.15) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Instagram:** Add `Enable developer menu` patch ([#6043](https://github.com/ReVanced/revanced-patches/issues/6043)) ([2154d89](https://github.com/ReVanced/revanced-patches/commit/2154d89242fd8d7f7460145d5d35a4f1986944a3))
|
||||||
|
|
||||||
|
# [5.42.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.13...v5.42.0-dev.14) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Instagram:** Add `Custom share domain` patch ([#5998](https://github.com/ReVanced/revanced-patches/issues/5998)) ([20c4131](https://github.com/ReVanced/revanced-patches/commit/20c413120bad97af6121718e76b22a1b5540aa44))
|
||||||
|
|
||||||
|
# [5.42.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.12...v5.42.0-dev.13) (2025-10-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Spotify:** Change `Hide Create button` patch to default off ([#6067](https://github.com/ReVanced/revanced-patches/issues/6067)) ([19949e1](https://github.com/ReVanced/revanced-patches/commit/19949e1695cc252ff0f94a33b6e3fb62e967d7fd))
|
||||||
|
|
||||||
|
# [5.42.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.11...v5.42.0-dev.12) (2025-10-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Custom branding:** Update ReVanced logo ([#6049](https://github.com/ReVanced/revanced-patches/issues/6049)) ([9441e7a](https://github.com/ReVanced/revanced-patches/commit/9441e7acb4817e12d1443d438ef6c448518bd614))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Instagram:** Add `Sanitize sharing links` patch ([#5986](https://github.com/ReVanced/revanced-patches/issues/5986)) ([963a4ef](https://github.com/ReVanced/revanced-patches/commit/963a4ef43fd513de7a2d7d019992f06b62fdcc10))
|
||||||
|
|
||||||
|
# [5.42.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.10...v5.42.0-dev.11) (2025-10-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube:** Resolve UI components not hiding for some users ([#6054](https://github.com/ReVanced/revanced-patches/issues/6054)) ([6b26346](https://github.com/ReVanced/revanced-patches/commit/6b2634691423f5ce25a28b3f2fbc420977b81748))
|
||||||
|
|
||||||
|
# [5.42.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.9...v5.42.0-dev.10) (2025-10-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof video streams:** Resolve playback dropping frames ([#6051](https://github.com/ReVanced/revanced-patches/issues/6051)) ([a62ee43](https://github.com/ReVanced/revanced-patches/commit/a62ee43441b197f5c8352ae373bb8919ad66f0bd))
|
||||||
|
|
||||||
|
# [5.42.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.8...v5.42.0-dev.9) (2025-10-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Custom branding:** Update ReVanced logo sizing ([#6029](https://github.com/ReVanced/revanced-patches/issues/6029)) ([ae4b947](https://github.com/ReVanced/revanced-patches/commit/ae4b9474d3fb62528fc21397c19954d31605e9da))
|
||||||
|
|
||||||
|
# [5.42.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.7...v5.42.0-dev.8) (2025-10-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Force original language:** Resolve some videos using Swedish audio track ([9d67316](https://github.com/ReVanced/revanced-patches/commit/9d6731660ba0e19b863d05d54aa04f74a879f69b))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube Music:** Add `Force original audio` patch ([#6036](https://github.com/ReVanced/revanced-patches/issues/6036)) ([d0d53d1](https://github.com/ReVanced/revanced-patches/commit/d0d53d109e451759a029326873adfa36fba12b23))
|
||||||
|
|
||||||
|
# [5.42.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.6...v5.42.0-dev.7) (2025-10-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Instagram:** Add `Open links externally` patch ([#6012](https://github.com/ReVanced/revanced-patches/issues/6012)) ([08e8ead](https://github.com/ReVanced/revanced-patches/commit/08e8ead04ffff47a4608a3db7aadc8d5feccd4ad))
|
||||||
|
|
||||||
|
# [5.42.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.5...v5.42.0-dev.6) (2025-09-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **X / Twitter:** Remove non functional and obsolete patch `Open links with app chooser` ([#6033](https://github.com/ReVanced/revanced-patches/issues/6033)) ([673609c](https://github.com/ReVanced/revanced-patches/commit/673609c2aa87988cdc138eab101b9750fe6a7b62))
|
||||||
|
|
||||||
|
# [5.42.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.4...v5.42.0-dev.5) (2025-09-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube Music:** Add `Custom branding` patch ([#6007](https://github.com/ReVanced/revanced-patches/issues/6007)) ([4c8b56f](https://github.com/ReVanced/revanced-patches/commit/4c8b56f5466b244737f501654eb7c5d34b6b2f88))
|
||||||
|
|
||||||
|
# [5.42.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.3...v5.42.0-dev.4) (2025-09-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube Music - GmsCore support:** Handle sharing links to certain apps such as Instagram ([#6026](https://github.com/ReVanced/revanced-patches/issues/6026)) ([328234f](https://github.com/ReVanced/revanced-patches/commit/328234f39ada81542e596f04e8ce410c787c15c8))
|
||||||
|
|
||||||
|
# [5.42.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.2...v5.42.0-dev.3) (2025-09-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Hide end screen cards:** Hide new type of end screen card ([#6027](https://github.com/ReVanced/revanced-patches/issues/6027)) ([76b0364](https://github.com/ReVanced/revanced-patches/commit/76b0364c5b5562c6a0d178d2bbe5b220f48aaca9))
|
||||||
|
|
||||||
# [5.42.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.1...v5.42.0-dev.2) (2025-09-27)
|
# [5.42.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.42.0-dev.1...v5.42.0-dev.2) (2025-09-27)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package app.revanced.extension.instagram.misc.links;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class OpenLinksExternallyPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean openExternally(String url) {
|
||||||
|
try {
|
||||||
|
// The "url" parameter to this function will be of the form.
|
||||||
|
// https://l.instagram.com/?u=<actual url>&e=<tracking id>
|
||||||
|
String actualUrl = Uri.parse(url).getQueryParameter("u");
|
||||||
|
if (actualUrl != null) {
|
||||||
|
Utils.openLink(actualUrl);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "openExternally failure", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package app.revanced.extension.instagram.misc.privacy;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class SanitizeSharingLinksPatch {
|
||||||
|
private static final LinkSanitizer sanitizer = new LinkSanitizer("igsh");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static String sanitizeSharingLink(String url) {
|
||||||
|
return sanitizer.sanitizeUrlString(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package app.revanced.extension.instagram.misc.share.domain;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class ChangeLinkSharingDomainPatch {
|
||||||
|
|
||||||
|
private static String getCustomShareDomain() {
|
||||||
|
// Method is modified during patching.
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static String setCustomShareDomain(String url) {
|
||||||
|
try {
|
||||||
|
Uri uri = Uri.parse(url);
|
||||||
|
Uri.Builder builder = uri
|
||||||
|
.buildUpon()
|
||||||
|
.authority(getCustomShareDomain())
|
||||||
|
.clearQuery();
|
||||||
|
|
||||||
|
String patchedUrl = builder.build().toString();
|
||||||
|
Logger.printInfo(() -> "Domain change from : " + url + " to: " + patchedUrl);
|
||||||
|
return patchedUrl;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "setCustomShareDomain failure with " + url, ex);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package app.revanced.extension.instagram.misc.share.privacy;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class SanitizeSharingLinksPatch {
|
||||||
|
private static final LinkSanitizer sanitizer = new LinkSanitizer("igsh");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static String sanitizeSharingLink(String url) {
|
||||||
|
return sanitizer.sanitizeUrlString(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ForceOriginalAudioPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void setEnabled() {
|
||||||
|
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
|
||||||
|
Settings.FORCE_ORIGINAL_AUDIO.get(),
|
||||||
|
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,6 @@ public class HideCastButtonPatch {
|
|||||||
* Injection point
|
* Injection point
|
||||||
*/
|
*/
|
||||||
public static void hideCastButton(View view) {
|
public static void hideCastButton(View view) {
|
||||||
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view);
|
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON, view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package app.revanced.extension.music.patches;
|
package app.revanced.extension.music.patches;
|
||||||
|
|
||||||
|
import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
import app.revanced.extension.music.settings.Settings;
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@@ -8,7 +11,7 @@ public class HideCategoryBarPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point
|
* Injection point
|
||||||
*/
|
*/
|
||||||
public static boolean hideCategoryBar() {
|
public static void hideCategoryBar(View view) {
|
||||||
return Settings.HIDE_CATEGORY_BAR.get();
|
hideViewBy0dpUnderCondition(Settings.HIDE_CATEGORY_BAR, view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,4 +32,6 @@ public class Settings extends BaseSettings {
|
|||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
|
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
|
||||||
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
|
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
|
||||||
|
|
||||||
|
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import android.preference.PreferenceScreen;
|
|||||||
import android.widget.Toolbar;
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
import app.revanced.extension.music.settings.MusicActivityHook;
|
import app.revanced.extension.music.settings.MusicActivityHook;
|
||||||
|
import app.revanced.extension.shared.GmsCoreSupport;
|
||||||
import app.revanced.extension.shared.Logger;
|
import app.revanced.extension.shared.Logger;
|
||||||
import app.revanced.extension.shared.Utils;
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +32,17 @@ public class MusicPreferenceFragment extends ToolbarPreferenceFragment {
|
|||||||
preferenceScreen = getPreferenceScreen();
|
preferenceScreen = getPreferenceScreen();
|
||||||
Utils.sortPreferenceGroups(preferenceScreen);
|
Utils.sortPreferenceGroups(preferenceScreen);
|
||||||
setPreferenceScreenToolbar(preferenceScreen);
|
setPreferenceScreenToolbar(preferenceScreen);
|
||||||
|
|
||||||
|
// Clunky work around until preferences are custom classes that manage themselves.
|
||||||
|
// Custom branding only works with non-root install. But the preferences must be
|
||||||
|
// added during patched because of difficulties detecting during patching if it's
|
||||||
|
// a root install. So instead the non-functional preferences are removed during
|
||||||
|
// runtime if the app is mount (root) installation.
|
||||||
|
if (GmsCoreSupport.isPackageNameOriginal()) {
|
||||||
|
removePreferences(
|
||||||
|
BaseSettings.CUSTOM_BRANDING_ICON.key,
|
||||||
|
BaseSettings.CUSTOM_BRANDING_NAME.key);
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "initialize failure", ex);
|
Logger.printException(() -> "initialize failure", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
4
extensions/samsung/radio/build.gradle.kts
Normal file
4
extensions/samsung/radio/build.gradle.kts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
dependencies {
|
||||||
|
compileOnly(project(":extensions:shared:library"))
|
||||||
|
compileOnly(project(":extensions:samsung:radio:stub"))
|
||||||
|
}
|
||||||
1
extensions/samsung/radio/src/main/AndroidManifest.xml
Normal file
1
extensions/samsung/radio/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest/>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package app.revanced.extension.samsung.radio.misc.fix.crash;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class FixCrashPatch {
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
* <p>
|
||||||
|
* Add the required permissions to the request list to avoid crashes on API 34+.
|
||||||
|
**/
|
||||||
|
public static final String[] fixPermissionRequestList(String[] perms) {
|
||||||
|
List<String> permsList = new ArrayList<>(Arrays.asList(perms));
|
||||||
|
if (permsList.contains("android.permission.POST_NOTIFICATIONS")) {
|
||||||
|
permsList.addAll(Arrays.asList("android.permission.RECORD_AUDIO", "android.permission.READ_PHONE_STATE", "android.permission.FOREGROUND_SERVICE_MICROPHONE"));
|
||||||
|
}
|
||||||
|
if (permsList.contains("android.permission.RECORD_AUDIO")) {
|
||||||
|
permsList.add("android.permission.FOREGROUND_SERVICE_MICROPHONE");
|
||||||
|
}
|
||||||
|
return permsList.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package app.revanced.extension.samsung.radio.restrictions.device;
|
||||||
|
|
||||||
|
import android.os.SemSystemProperties;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class BypassDeviceChecksPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
* <p>
|
||||||
|
* Check if the device has the required hardware
|
||||||
|
**/
|
||||||
|
public static final boolean checkIfDeviceIsIncompatible(String[] deviceList) {
|
||||||
|
String currentDevice = SemSystemProperties.getSalesCode();
|
||||||
|
return Arrays.asList(deviceList).contains(currentDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
extensions/samsung/radio/stub/build.gradle.kts
Normal file
17
extensions/samsung/radio/stub/build.gradle.kts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
plugins {
|
||||||
|
alias(libs.plugins.android.library)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "app.revanced.extension"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<manifest/>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package android.os;
|
||||||
|
|
||||||
|
public class SemSystemProperties {
|
||||||
|
public static String getSalesCode() {
|
||||||
|
throw new UnsupportedOperationException("Stub");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,9 +31,6 @@ import app.revanced.extension.shared.ui.CustomDialog;
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class GmsCoreSupport {
|
public class GmsCoreSupport {
|
||||||
private static final String PACKAGE_NAME_YOUTUBE = "com.google.android.youtube";
|
|
||||||
private static final String PACKAGE_NAME_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music";
|
|
||||||
|
|
||||||
private static final String GMS_CORE_PACKAGE_NAME
|
private static final String GMS_CORE_PACKAGE_NAME
|
||||||
= getGmsCoreVendorGroupId() + ".android.gms";
|
= getGmsCoreVendorGroupId() + ".android.gms";
|
||||||
private static final Uri GMS_CORE_PROVIDER
|
private static final Uri GMS_CORE_PROVIDER
|
||||||
@@ -53,6 +50,20 @@ public class GmsCoreSupport {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static volatile Boolean DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED;
|
private static volatile Boolean DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED;
|
||||||
|
|
||||||
|
private static String getOriginalPackageName() {
|
||||||
|
return null; // Modified during patching.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If the current package name is the same as the original unpatched app.
|
||||||
|
* If `GmsCore support` was not included during patching, this returns true;
|
||||||
|
*/
|
||||||
|
public static boolean isPackageNameOriginal() {
|
||||||
|
String originalPackageName = getOriginalPackageName();
|
||||||
|
return originalPackageName == null
|
||||||
|
|| originalPackageName.equals(Utils.getContext().getPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
private static void open(String queryOrLink) {
|
private static void open(String queryOrLink) {
|
||||||
Logger.printInfo(() -> "Opening link: " + queryOrLink);
|
Logger.printInfo(() -> "Opening link: " + queryOrLink);
|
||||||
|
|
||||||
@@ -113,11 +124,10 @@ public class GmsCoreSupport {
|
|||||||
// Verify the user has not included GmsCore for a root installation.
|
// Verify the user has not included GmsCore for a root installation.
|
||||||
// GmsCore Support changes the package name, but with a mounted installation
|
// GmsCore Support changes the package name, but with a mounted installation
|
||||||
// all manifest changes are ignored and the original package name is used.
|
// all manifest changes are ignored and the original package name is used.
|
||||||
String packageName = context.getPackageName();
|
if (isPackageNameOriginal()) {
|
||||||
if (packageName.equals(PACKAGE_NAME_YOUTUBE) || packageName.equals(PACKAGE_NAME_YOUTUBE_MUSIC)) {
|
|
||||||
Logger.printInfo(() -> "App is mounted with root, but GmsCore patch was included");
|
Logger.printInfo(() -> "App is mounted with root, but GmsCore patch was included");
|
||||||
// Cannot use localize text here, since the app will load
|
// Cannot use localize text here, since the app will load resources
|
||||||
// resources from the unpatched app and all patch strings are missing.
|
// from the unpatched app and all patch strings are missing.
|
||||||
Utils.showToastLong("The 'GmsCore support' patch breaks mount installations");
|
Utils.showToastLong("The 'GmsCore support' patch breaks mount installations");
|
||||||
|
|
||||||
// Do not exit. If the app exits before launch completes (and without
|
// Do not exit. If the app exits before launch completes (and without
|
||||||
@@ -250,8 +260,7 @@ public class GmsCoreSupport {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modified by a patch. Do not touch.
|
|
||||||
private static String getGmsCoreVendorGroupId() {
|
private static String getGmsCoreVendorGroupId() {
|
||||||
return "app.revanced";
|
return "app.revanced"; // Modified during patching.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import android.content.res.Configuration;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@@ -696,6 +697,18 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openLink(String url) {
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent("android.intent.action.VIEW", Uri.parse(url));
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
|
||||||
|
Logger.printInfo(() -> "Opening link with external browser: " + intent);
|
||||||
|
getContext().startActivity(intent);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "openLink failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum NetworkType {
|
public enum NetworkType {
|
||||||
NONE,
|
NONE,
|
||||||
MOBILE,
|
MOBILE,
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class CheckWatchHistoryDomainNameResolutionPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*
|
*
|
||||||
* Checks if s.youtube.com is blacklisted and playback history will fail to work.
|
* Checks if YouTube watch history endpoint cannot be reached.
|
||||||
*/
|
*/
|
||||||
public static void checkDnsResolver(Activity context) {
|
public static void checkDnsResolver(Activity context) {
|
||||||
if (!Utils.isNetworkConnected() || !BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return;
|
if (!Utils.isNetworkConnected() || !BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.get()) return;
|
||||||
@@ -67,28 +67,20 @@ public class CheckWatchHistoryDomainNameResolutionPatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Utils.runOnMainThread(() -> {
|
Utils.runOnMainThread(() -> {
|
||||||
try {
|
Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create(
|
||||||
// Create the custom dialog.
|
context,
|
||||||
Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create(
|
str("revanced_check_watch_history_domain_name_dialog_title"), // Title.
|
||||||
context,
|
Html.fromHtml(str("revanced_check_watch_history_domain_name_dialog_message")), // Message (HTML).
|
||||||
str("revanced_check_watch_history_domain_name_dialog_title"), // Title.
|
null, // No EditText.
|
||||||
Html.fromHtml(str("revanced_check_watch_history_domain_name_dialog_message")), // Message (HTML).
|
null, // OK button text.
|
||||||
null, // No EditText.
|
() -> {}, // OK button action (just dismiss).
|
||||||
null, // OK button text.
|
null, // No cancel button.
|
||||||
() -> {}, // OK button action (just dismiss).
|
str("revanced_check_watch_history_domain_name_dialog_ignore"), // Neutral button text.
|
||||||
() -> {}, // Cancel button action (just dismiss).
|
() -> BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore).
|
||||||
str("revanced_check_watch_history_domain_name_dialog_ignore"), // Neutral button text.
|
true // Dismiss dialog on Neutral button click.
|
||||||
() -> BaseSettings.CHECK_WATCH_HISTORY_DOMAIN_NAME.save(false), // Neutral button action (Ignore).
|
);
|
||||||
true // Dismiss dialog on Neutral button click.
|
|
||||||
);
|
|
||||||
|
|
||||||
// Show the dialog.
|
Utils.showDialog(context, dialogPair.first, false, null);
|
||||||
Dialog dialog = dialogPair.first;
|
|
||||||
|
|
||||||
Utils.showDialog(context, dialog, false, null);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Logger.printException(() -> "checkDnsResolver dialog creation failure", ex);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "checkDnsResolver failure", ex);
|
Logger.printException(() -> "checkDnsResolver failure", ex);
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package app.revanced.extension.shared.patches;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Color;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.GmsCoreSupport;
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch shared by YouTube and YT Music.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class CustomBrandingPatch {
|
||||||
|
|
||||||
|
// Important: In the future, additional branding themes can be added but all existing and prior
|
||||||
|
// themes cannot be removed or renamed.
|
||||||
|
//
|
||||||
|
// This is because if a user has a branding theme selected, then only that launch alias is enabled.
|
||||||
|
// If a future update removes or renames that alias, then after updating the app is effectively
|
||||||
|
// broken and it cannot be opened and not even clearing the app data will fix it.
|
||||||
|
// In that situation the only fix is to completely uninstall and reinstall again.
|
||||||
|
//
|
||||||
|
// The most that can be done is to hide a theme from the UI and keep the alias with dummy data.
|
||||||
|
public enum BrandingTheme {
|
||||||
|
/**
|
||||||
|
* Original unpatched icon.
|
||||||
|
*/
|
||||||
|
ORIGINAL,
|
||||||
|
ROUNDED,
|
||||||
|
MINIMAL,
|
||||||
|
SCALED,
|
||||||
|
/**
|
||||||
|
* User provided custom icon.
|
||||||
|
*/
|
||||||
|
CUSTOM;
|
||||||
|
|
||||||
|
private String packageAndNameIndexToClassAlias(String packageName, int appIndex) {
|
||||||
|
if (appIndex <= 0) {
|
||||||
|
throw new IllegalArgumentException("App index starts at index 1");
|
||||||
|
}
|
||||||
|
return packageName + ".revanced_" + name().toLowerCase(Locale.US) + '_' + appIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int notificationSmallIcon;
|
||||||
|
|
||||||
|
static {
|
||||||
|
BrandingTheme branding = BaseSettings.CUSTOM_BRANDING_ICON.get();
|
||||||
|
if (branding == BrandingTheme.ORIGINAL) {
|
||||||
|
notificationSmallIcon = 0;
|
||||||
|
} else {
|
||||||
|
// Original icon is quantum_ic_video_youtube_white_24
|
||||||
|
String iconName = "revanced_notification_icon";
|
||||||
|
if (branding == BrandingTheme.CUSTOM) {
|
||||||
|
iconName += "_custom";
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationSmallIcon = Utils.getResourceIdentifier(iconName, "drawable");
|
||||||
|
if (notificationSmallIcon == 0) {
|
||||||
|
Logger.printException(() -> "Could not load notification small icon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void setNotificationIcon(Notification.Builder builder) {
|
||||||
|
try {
|
||||||
|
if (notificationSmallIcon != 0) {
|
||||||
|
builder.setSmallIcon(notificationSmallIcon)
|
||||||
|
.setColor(Color.TRANSPARENT); // Remove YT red tint.
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "setNotificationIcon failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*
|
||||||
|
* The total number of app name aliases, including dummy aliases.
|
||||||
|
*/
|
||||||
|
private static int numberOfPresetAppNames() {
|
||||||
|
// Modified during patching.
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
public static void setBranding() {
|
||||||
|
try {
|
||||||
|
if (GmsCoreSupport.isPackageNameOriginal()) {
|
||||||
|
Logger.printInfo(() -> "App is root mounted. Cannot dynamically change app icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context context = Utils.getContext();
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
String packageName = context.getPackageName();
|
||||||
|
|
||||||
|
BrandingTheme selectedBranding = BaseSettings.CUSTOM_BRANDING_ICON.get();
|
||||||
|
final int selectedNameIndex = BaseSettings.CUSTOM_BRANDING_NAME.get();
|
||||||
|
ComponentName componentToEnable = null;
|
||||||
|
ComponentName defaultComponent = null;
|
||||||
|
List<ComponentName> componentsToDisable = new ArrayList<>();
|
||||||
|
|
||||||
|
for (BrandingTheme theme : BrandingTheme.values()) {
|
||||||
|
// Must always update all aliases including custom alias (last index).
|
||||||
|
final int numberOfPresetAppNames = numberOfPresetAppNames();
|
||||||
|
|
||||||
|
// App name indices starts at 1.
|
||||||
|
for (int index = 1; index <= numberOfPresetAppNames; index++) {
|
||||||
|
String aliasClass = theme.packageAndNameIndexToClassAlias(packageName, index);
|
||||||
|
ComponentName component = new ComponentName(packageName, aliasClass);
|
||||||
|
if (defaultComponent == null) {
|
||||||
|
// Default is always the first alias.
|
||||||
|
defaultComponent = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == selectedNameIndex && theme == selectedBranding) {
|
||||||
|
componentToEnable = component;
|
||||||
|
} else {
|
||||||
|
componentsToDisable.add(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentToEnable == null) {
|
||||||
|
// User imported a bad app name index value. Either the imported data
|
||||||
|
// was corrupted, or they previously had custom name enabled and the app
|
||||||
|
// no longer has a custom name specified.
|
||||||
|
Utils.showToastLong("Custom branding reset");
|
||||||
|
BaseSettings.CUSTOM_BRANDING_ICON.resetToDefault();
|
||||||
|
BaseSettings.CUSTOM_BRANDING_NAME.resetToDefault();
|
||||||
|
|
||||||
|
componentToEnable = defaultComponent;
|
||||||
|
componentsToDisable.remove(defaultComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ComponentName disable : componentsToDisable) {
|
||||||
|
pm.setComponentEnabledSetting(disable,
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use info logging because if the alias status become corrupt the app cannot launch.
|
||||||
|
ComponentName componentToEnableFinal = componentToEnable;
|
||||||
|
Logger.printInfo(() -> "Enabling: " + componentToEnableFinal.getClassName());
|
||||||
|
|
||||||
|
pm.setComponentEnabledSetting(componentToEnable,
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "setBranding failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package app.revanced.extension.shared.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.settings.AppLanguage;
|
||||||
|
import app.revanced.extension.shared.spoof.ClientType;
|
||||||
|
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ForceOriginalAudioPatch {
|
||||||
|
|
||||||
|
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
|
||||||
|
|
||||||
|
private static volatile boolean enabled;
|
||||||
|
|
||||||
|
public static void setEnabled(boolean isEnabled, ClientType client) {
|
||||||
|
enabled = isEnabled;
|
||||||
|
|
||||||
|
if (isEnabled && !client.useAuth && !client.supportsMultiAudioTracks) {
|
||||||
|
// If client spoofing does not use authentication and lacks multi-audio streams,
|
||||||
|
// then can use any language code for the request and if that requested language is
|
||||||
|
// not available YT uses the original audio language. Authenticated requests ignore
|
||||||
|
// the language code and always use the account language. Use a language that is
|
||||||
|
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
|
||||||
|
// but the language is also supported natively by the Meta Quest device that
|
||||||
|
// Android VR is spoofing.
|
||||||
|
AppLanguage override = AppLanguage.NB; // Norwegian Bokmal.
|
||||||
|
Logger.printDebug(() -> "Setting language override: " + override);
|
||||||
|
SpoofVideoStreamsPatch.setLanguageOverride(override);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean ignoreDefaultAudioStream(boolean original) {
|
||||||
|
if (enabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
|
||||||
|
try {
|
||||||
|
if (!enabled) {
|
||||||
|
return isDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioTrackId.isEmpty()) {
|
||||||
|
// Older app targets can have empty audio tracks and these might be placeholders.
|
||||||
|
// The real audio tracks are called after these.
|
||||||
|
return isDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
|
||||||
|
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
|
||||||
|
|
||||||
|
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
|
||||||
|
if (isOriginal) {
|
||||||
|
Logger.printDebug(() -> "Using audio: " + audioTrackId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isOriginal;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "isDefaultAudioStream failure", ex);
|
||||||
|
return isDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package app.revanced.extension.shared.patches;
|
package app.revanced.extension.shared.patches;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||||
import app.revanced.extension.shared.settings.BaseSettings;
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -7,17 +8,18 @@ import app.revanced.extension.shared.settings.BaseSettings;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class SanitizeSharingLinksPatch {
|
public final class SanitizeSharingLinksPatch {
|
||||||
private static final String NEW_TRACKING_PARAMETER_REGEX = ".si=.+";
|
|
||||||
private static final String OLD_TRACKING_PARAMETER_REGEX = ".feature=.+";
|
private static final LinkSanitizer sanitizer = new LinkSanitizer(
|
||||||
|
"si",
|
||||||
|
"feature" // Old tracking parameter name, and may be obsolete.
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static String sanitize(String url) {
|
public static String sanitize(String url) {
|
||||||
if (BaseSettings.SANITIZE_SHARED_LINKS.get()) {
|
if (BaseSettings.SANITIZE_SHARED_LINKS.get()) {
|
||||||
url = url
|
url = sanitizer.sanitizeUrlString(url);
|
||||||
.replaceAll(NEW_TRACKING_PARAMETER_REGEX, "")
|
|
||||||
.replaceAll(OLD_TRACKING_PARAMETER_REGEX, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) {
|
if (BaseSettings.REPLACE_MUSIC_LINKS_WITH_YOUTUBE.get()) {
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package app.revanced.extension.shared.privacy;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips away specific parameters from URLs.
|
||||||
|
*/
|
||||||
|
public class LinkSanitizer {
|
||||||
|
|
||||||
|
private final Collection<String> parametersToRemove;
|
||||||
|
|
||||||
|
public LinkSanitizer(String ... parametersToRemove) {
|
||||||
|
final int parameterCount = parametersToRemove.length;
|
||||||
|
|
||||||
|
// List is faster if only checking a few parameters.
|
||||||
|
this.parametersToRemove = parameterCount > 4
|
||||||
|
? Set.of(parametersToRemove)
|
||||||
|
: List.of(parametersToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String sanitizeUrlString(String url) {
|
||||||
|
try {
|
||||||
|
return sanitizeUri(Uri.parse(url)).toString();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "sanitizeUrlString failure: " + url, ex);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri sanitizeUri(Uri uri) {
|
||||||
|
try {
|
||||||
|
Uri.Builder builder = uri.buildUpon().clearQuery();
|
||||||
|
|
||||||
|
if (!parametersToRemove.isEmpty()) {
|
||||||
|
for (String paramName : uri.getQueryParameterNames()) {
|
||||||
|
if (!parametersToRemove.contains(paramName)) {
|
||||||
|
for (String value : uri.getQueryParameters(paramName)) {
|
||||||
|
builder.appendQueryParameter(paramName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Uri sanitizedUrl = builder.build();
|
||||||
|
Logger.printInfo(() -> "Sanitized url: " + uri + " to: " + sanitizedUrl);
|
||||||
|
|
||||||
|
return sanitizedUrl;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "sanitizeUri failure: " + uri, ex);
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,8 +36,8 @@ public enum AppLanguage {
|
|||||||
FR,
|
FR,
|
||||||
GL,
|
GL,
|
||||||
GU,
|
GU,
|
||||||
HI,
|
|
||||||
HE, // App uses obsolete 'IW' and not the modern 'HE' ISO code.
|
HE, // App uses obsolete 'IW' and not the modern 'HE' ISO code.
|
||||||
|
HI,
|
||||||
HR,
|
HR,
|
||||||
HU,
|
HU,
|
||||||
HY,
|
HY,
|
||||||
@@ -60,9 +60,9 @@ public enum AppLanguage {
|
|||||||
MR,
|
MR,
|
||||||
MS,
|
MS,
|
||||||
MY,
|
MY,
|
||||||
|
NB,
|
||||||
NE,
|
NE,
|
||||||
NL,
|
NL,
|
||||||
NB,
|
|
||||||
OR,
|
OR,
|
||||||
PA,
|
PA,
|
||||||
PL,
|
PL,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package app.revanced.extension.shared.settings;
|
|||||||
|
|
||||||
import static java.lang.Boolean.FALSE;
|
import static java.lang.Boolean.FALSE;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static app.revanced.extension.shared.patches.CustomBrandingPatch.BrandingTheme;
|
||||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||||
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
|
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
|
||||||
|
|
||||||
@@ -40,4 +41,7 @@ public class BaseSettings {
|
|||||||
public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE);
|
public static final BooleanSetting REPLACE_MUSIC_LINKS_WITH_YOUTUBE = new BooleanSetting("revanced_replace_music_with_youtube", FALSE);
|
||||||
|
|
||||||
public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false);
|
public static final BooleanSetting CHECK_WATCH_HISTORY_DOMAIN_NAME = new BooleanSetting("revanced_check_watch_history_domain_name", TRUE, false, false);
|
||||||
|
|
||||||
|
public static final EnumSetting<BrandingTheme> CUSTOM_BRANDING_ICON = new EnumSetting<>("revanced_custom_branding_icon", BrandingTheme.ORIGINAL, true);
|
||||||
|
public static final IntegerSetting CUSTOM_BRANDING_NAME = new IntegerSetting("revanced_custom_branding_name", 1, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.extension.youtube.settings.preference;
|
package app.revanced.extension.shared.settings.preference;
|
||||||
|
|
||||||
import static app.revanced.extension.shared.StringRef.str;
|
import static app.revanced.extension.shared.StringRef.str;
|
||||||
|
|
||||||
@@ -6,17 +6,17 @@ import android.content.Context;
|
|||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.shared.spoof.ClientType;
|
import app.revanced.extension.shared.spoof.ClientType;
|
||||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
|
||||||
|
|
||||||
@SuppressWarnings({"deprecation", "unused"})
|
@SuppressWarnings({"deprecation", "unused"})
|
||||||
public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
|
public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
|
||||||
|
|
||||||
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
|
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
|
||||||
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|
||||||
|| !(Settings.SPOOF_VIDEO_STREAMS.get()
|
|| !(BaseSettings.SPOOF_VIDEO_STREAMS.get()
|
||||||
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR);
|
&& SpoofVideoStreamsPatch.getPreferredClient() == ClientType.ANDROID_CREATOR);
|
||||||
|
|
||||||
{
|
{
|
||||||
if (!available) {
|
if (!available) {
|
||||||
@@ -5,6 +5,7 @@ import static app.revanced.extension.shared.Utils.dipToPixels;
|
|||||||
import static app.revanced.extension.shared.requests.Route.Method.GET;
|
import static app.revanced.extension.shared.requests.Route.Method.GET;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -125,6 +126,8 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
|
|
||||||
{
|
{
|
||||||
setOnPreferenceClickListener(pref -> {
|
setOnPreferenceClickListener(pref -> {
|
||||||
|
Context context = pref.getContext();
|
||||||
|
|
||||||
// Show a progress spinner if the social links are not fetched yet.
|
// Show a progress spinner if the social links are not fetched yet.
|
||||||
if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
|
||||||
// Show a progress spinner, but only if the api fetch takes more than a half a second.
|
// Show a progress spinner, but only if the api fetch takes more than a half a second.
|
||||||
@@ -137,17 +140,18 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner);
|
handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner);
|
||||||
|
|
||||||
Utils.runOnBackgroundThread(() ->
|
Utils.runOnBackgroundThread(() ->
|
||||||
fetchLinksAndShowDialog(handler, showDialogRunnable, progress));
|
fetchLinksAndShowDialog(context, handler, showDialogRunnable, progress));
|
||||||
} else {
|
} else {
|
||||||
// No network call required and can run now.
|
// No network call required and can run now.
|
||||||
fetchLinksAndShowDialog(null, null, null);
|
fetchLinksAndShowDialog(context, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchLinksAndShowDialog(@Nullable Handler handler,
|
private void fetchLinksAndShowDialog(Context context,
|
||||||
|
@Nullable Handler handler,
|
||||||
Runnable showDialogRunnable,
|
Runnable showDialogRunnable,
|
||||||
@Nullable ProgressDialog progress) {
|
@Nullable ProgressDialog progress) {
|
||||||
WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
|
WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
|
||||||
@@ -164,7 +168,17 @@ public class ReVancedAboutPreference extends Preference {
|
|||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
handler.removeCallbacks(showDialogRunnable);
|
handler.removeCallbacks(showDialogRunnable);
|
||||||
}
|
}
|
||||||
if (progress != null) {
|
|
||||||
|
// Don't continue if the activity is done. To test this tap the
|
||||||
|
// about dialog and immediately press back before the dialog can show.
|
||||||
|
if (context instanceof Activity activity) {
|
||||||
|
if (activity.isFinishing() || activity.isDestroyed()) {
|
||||||
|
Logger.printDebug(() -> "Not showing about dialog, activity is closed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress != null && progress.isShowing()) {
|
||||||
progress.dismiss();
|
progress.dismiss();
|
||||||
}
|
}
|
||||||
new WebViewDialog(getContext(), htmlDialog).show();
|
new WebViewDialog(getContext(), htmlDialog).show();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.graphics.Insets;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
|
import android.preference.PreferenceGroup;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -22,6 +23,24 @@ import app.revanced.extension.shared.settings.BaseActivityHook;
|
|||||||
|
|
||||||
@SuppressWarnings({"deprecation", "NewApi"})
|
@SuppressWarnings({"deprecation", "NewApi"})
|
||||||
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
|
public class ToolbarPreferenceFragment extends AbstractPreferenceFragment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the list of preferences from this fragment, if they exist.
|
||||||
|
* @param keys Preference keys.
|
||||||
|
*/
|
||||||
|
protected void removePreferences(String ... keys) {
|
||||||
|
for (String key : keys) {
|
||||||
|
Preference pref = findPreference(key);
|
||||||
|
if (pref != null) {
|
||||||
|
PreferenceGroup parent = pref.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
Logger.printDebug(() -> "Removing preference: " + key);
|
||||||
|
parent.removePreference(pref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets toolbar for all nested preference screens.
|
* Sets toolbar for all nested preference screens.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public enum ClientType {
|
|||||||
"132.0.6808.3",
|
"132.0.6808.3",
|
||||||
"1.61.48",
|
"1.61.48",
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
"Android VR 1.61"
|
"Android VR 1.61"
|
||||||
),
|
),
|
||||||
/**
|
/**
|
||||||
@@ -50,6 +51,7 @@ public enum ClientType {
|
|||||||
"107.0.5284.2",
|
"107.0.5284.2",
|
||||||
"1.43.32",
|
"1.43.32",
|
||||||
ANDROID_VR_1_61_48.useAuth,
|
ANDROID_VR_1_61_48.useAuth,
|
||||||
|
ANDROID_VR_1_61_48.supportsMultiAudioTracks,
|
||||||
"Android VR 1.43"
|
"Android VR 1.43"
|
||||||
),
|
),
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +71,7 @@ public enum ClientType {
|
|||||||
"132.0.6779.0",
|
"132.0.6779.0",
|
||||||
"23.47.101",
|
"23.47.101",
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
"Android Studio"
|
"Android Studio"
|
||||||
),
|
),
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +86,7 @@ public enum ClientType {
|
|||||||
"0.1",
|
"0.1",
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15",
|
||||||
false,
|
false,
|
||||||
|
false,
|
||||||
"visionOS"
|
"visionOS"
|
||||||
),
|
),
|
||||||
/**
|
/**
|
||||||
@@ -107,6 +111,7 @@ public enum ClientType {
|
|||||||
"19.22.3",
|
"19.22.3",
|
||||||
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
|
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
|
||||||
false,
|
false,
|
||||||
|
true,
|
||||||
"iPadOS"
|
"iPadOS"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -180,6 +185,11 @@ public enum ClientType {
|
|||||||
*/
|
*/
|
||||||
public final boolean useAuth;
|
public final boolean useAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the client supports multiple audio tracks.
|
||||||
|
*/
|
||||||
|
public final boolean supportsMultiAudioTracks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Friendly name displayed in stats for nerds.
|
* Friendly name displayed in stats for nerds.
|
||||||
*/
|
*/
|
||||||
@@ -200,6 +210,7 @@ public enum ClientType {
|
|||||||
@NonNull String cronetVersion,
|
@NonNull String cronetVersion,
|
||||||
String clientVersion,
|
String clientVersion,
|
||||||
boolean useAuth,
|
boolean useAuth,
|
||||||
|
boolean supportsMultiAudioTracks,
|
||||||
String friendlyName) {
|
String friendlyName) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
@@ -213,6 +224,7 @@ public enum ClientType {
|
|||||||
this.cronetVersion = cronetVersion;
|
this.cronetVersion = cronetVersion;
|
||||||
this.clientVersion = clientVersion;
|
this.clientVersion = clientVersion;
|
||||||
this.useAuth = useAuth;
|
this.useAuth = useAuth;
|
||||||
|
this.supportsMultiAudioTracks = supportsMultiAudioTracks;
|
||||||
this.friendlyName = friendlyName;
|
this.friendlyName = friendlyName;
|
||||||
|
|
||||||
Locale defaultLocale = Locale.getDefault();
|
Locale defaultLocale = Locale.getDefault();
|
||||||
@@ -238,6 +250,7 @@ public enum ClientType {
|
|||||||
String clientVersion,
|
String clientVersion,
|
||||||
String userAgent,
|
String userAgent,
|
||||||
boolean useAuth,
|
boolean useAuth,
|
||||||
|
boolean supportsMultiAudioTracks,
|
||||||
String friendlyName) {
|
String friendlyName) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.clientName = clientName;
|
this.clientName = clientName;
|
||||||
@@ -248,6 +261,7 @@ public enum ClientType {
|
|||||||
this.clientVersion = clientVersion;
|
this.clientVersion = clientVersion;
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
this.useAuth = useAuth;
|
this.useAuth = useAuth;
|
||||||
|
this.supportsMultiAudioTracks = supportsMultiAudioTracks;
|
||||||
this.friendlyName = friendlyName;
|
this.friendlyName = friendlyName;
|
||||||
this.packageName = null;
|
this.packageName = null;
|
||||||
this.androidSdkVersion = null;
|
this.androidSdkVersion = null;
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class SpoofVideoStreamsPatch {
|
public class SpoofVideoStreamsPatch {
|
||||||
|
|
||||||
|
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Domain used for internet connectivity verification.
|
* Domain used for internet connectivity verification.
|
||||||
* It has an empty response body and is only used to check for a 204 response code.
|
* It has an empty response body and is only used to check for a 204 response code.
|
||||||
@@ -39,7 +47,7 @@ public class SpoofVideoStreamsPatch {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static volatile AppLanguage languageOverride;
|
private static volatile AppLanguage languageOverride;
|
||||||
|
|
||||||
private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_61_48;
|
private static volatile ClientType preferredClient = ClientType.ANDROID_VR_1_43_32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If this patch was included during patching.
|
* @return If this patch was included during patching.
|
||||||
@@ -66,6 +74,10 @@ public class SpoofVideoStreamsPatch {
|
|||||||
StreamingDataRequest.setClientOrderToUse(availableClients, client);
|
StreamingDataRequest.setClientOrderToUse(availableClients, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ClientType getPreferredClient() {
|
||||||
|
return preferredClient;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean spoofingToClientWithNoMultiAudioStreams() {
|
public static boolean spoofingToClientWithNoMultiAudioStreams() {
|
||||||
return isPatchIncluded()
|
return isPatchIncluded()
|
||||||
&& SPOOF_STREAMING_DATA
|
&& SPOOF_STREAMING_DATA
|
||||||
@@ -317,11 +329,4 @@ public class SpoofVideoStreamsPatch {
|
|||||||
|
|
||||||
return videoFormat;
|
return videoFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable() {
|
|
||||||
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
package app.revanced.extension.spotify.misc.privacy;
|
package app.revanced.extension.spotify.misc.privacy;
|
||||||
|
|
||||||
import android.net.Uri;
|
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import app.revanced.extension.shared.Logger;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class SanitizeSharingLinksPatch {
|
public final class SanitizeSharingLinksPatch {
|
||||||
|
|
||||||
/**
|
private static final LinkSanitizer sanitizer = new LinkSanitizer(
|
||||||
* Parameters that are considered undesirable and should be stripped away.
|
|
||||||
*/
|
|
||||||
private static final List<String> SHARE_PARAMETERS_TO_REMOVE = List.of(
|
|
||||||
"si", // Share tracking parameter.
|
"si", // Share tracking parameter.
|
||||||
"utm_source" // Share source, such as "copy-link".
|
"utm_source" // Share source, such as "copy-link".
|
||||||
);
|
);
|
||||||
@@ -20,25 +13,7 @@ public final class SanitizeSharingLinksPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static String sanitizeUrl(String url) {
|
public static String sanitizeSharingLink(String url) {
|
||||||
try {
|
return sanitizer.sanitizeUrlString(url);
|
||||||
Uri uri = Uri.parse(url);
|
|
||||||
Uri.Builder builder = uri.buildUpon().clearQuery();
|
|
||||||
|
|
||||||
for (String paramName : uri.getQueryParameterNames()) {
|
|
||||||
if (!SHARE_PARAMETERS_TO_REMOVE.contains(paramName)) {
|
|
||||||
for (String value : uri.getQueryParameters(paramName)) {
|
|
||||||
builder.appendQueryParameter(paramName, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String sanitizedUrl = builder.build().toString();
|
|
||||||
Logger.printInfo(() -> "Sanitized url " + url + " to " + sanitizedUrl);
|
|
||||||
return sanitizedUrl;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Logger.printException(() -> "sanitizeUrl failure with " + url, ex);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
|
|||||||
public void addPreferences(Context context) {
|
public void addPreferences(Context context) {
|
||||||
addPreference(new ReVancedTikTokAboutPreference(context));
|
addPreference(new ReVancedTikTokAboutPreference(context));
|
||||||
|
|
||||||
|
addPreference(new TogglePreference(context,
|
||||||
|
"Sanitize sharing links",
|
||||||
|
"Remove tracking parameters from shared links.",
|
||||||
|
BaseSettings.SANITIZE_SHARED_LINKS
|
||||||
|
));
|
||||||
|
|
||||||
addPreference(new TogglePreference(context,
|
addPreference(new TogglePreference(context,
|
||||||
"Enable debug log",
|
"Enable debug log",
|
||||||
"Show extension debug log.",
|
"Show extension debug log.",
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package app.revanced.extension.tiktok.share;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
import app.revanced.extension.shared.privacy.LinkSanitizer;
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public final class ShareUrlSanitizer {
|
||||||
|
|
||||||
|
private static final LinkSanitizer sanitizer = new LinkSanitizer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point for setting check.
|
||||||
|
*/
|
||||||
|
public static boolean shouldSanitize() {
|
||||||
|
return BaseSettings.SANITIZE_SHARED_LINKS.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point for URL sanitization.
|
||||||
|
*/
|
||||||
|
public static String sanitizeShareUrl(final String url) {
|
||||||
|
if (url == null || url.isEmpty()) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sanitizer.sanitizeUrlString(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,3 @@
|
|||||||
// Do not remove. Necessary for the extension plugin to be applied to the project.
|
dependencies {
|
||||||
|
compileOnly(project(":extensions:shared:library"))
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,30 @@
|
|||||||
package app.revanced.twitter.patches.links;
|
package app.revanced.twitter.patches.links;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public final class ChangeLinkSharingDomainPatch {
|
public final class ChangeLinkSharingDomainPatch {
|
||||||
private static final String DOMAIN_NAME = "https://fxtwitter.com";
|
private static final String LINK_FORMAT = "https://%s/%s/status/%s";
|
||||||
private static final String LINK_FORMAT = "%s/%s/status/%s";
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method is modified during patching. Do not change.
|
||||||
|
*/
|
||||||
|
private static String getShareDomain() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO remove this once changeLinkSharingDomainResourcePatch is restored
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
public static String formatResourceLink(Object... formatArgs) {
|
public static String formatResourceLink(Object... formatArgs) {
|
||||||
String username = (String) formatArgs[0];
|
String username = (String) formatArgs[0];
|
||||||
String tweetId = (String) formatArgs[1];
|
String tweetId = (String) formatArgs[1];
|
||||||
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
public static String formatLink(long tweetId, String username) {
|
public static String formatLink(long tweetId, String username) {
|
||||||
return String.format(LINK_FORMAT, DOMAIN_NAME, username, tweetId);
|
return String.format(LINK_FORMAT, getShareDomain(), username, tweetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,18 @@ package app.revanced.twitter.patches.links;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Logger;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public final class OpenLinksWithAppChooserPatch {
|
public final class OpenLinksWithAppChooserPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
public static void openWithChooser(final Context context, final Intent intent) {
|
public static void openWithChooser(final Context context, final Intent intent) {
|
||||||
Log.d("ReVanced", "Opening intent with chooser: " + intent);
|
Logger.printInfo(() -> "Opening intent with chooser: " + intent);
|
||||||
|
|
||||||
intent.setAction("android.intent.action.VIEW");
|
intent.setAction("android.intent.action.VIEW");
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,25 @@ public class ChangeHeaderPatch {
|
|||||||
DEFAULT(null, null),
|
DEFAULT(null, null),
|
||||||
REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"),
|
REGULAR("ytWordmarkHeader", "yt_ringo2_wordmark_header"),
|
||||||
PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"),
|
PREMIUM("ytPremiumWordmarkHeader", "yt_ringo2_premium_wordmark_header"),
|
||||||
REVANCED("revanced_header_logo", "revanced_header_logo"),
|
ROUNDED("revanced_header_rounded"),
|
||||||
REVANCED_MINIMAL("revanced_header_logo_minimal", "revanced_header_logo_minimal"),
|
MINIMAL("revanced_header_minimal"),
|
||||||
CUSTOM("custom_header", "custom_header");
|
CUSTOM("revanced_header_custom"),
|
||||||
|
|
||||||
|
// Old enum names for data migration. TODO: Eventually delete these.
|
||||||
|
@Deprecated
|
||||||
|
REVANCED(ROUNDED.attributeName),
|
||||||
|
@Deprecated
|
||||||
|
REVANCED_MINIMAL(MINIMAL.attributeName);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String attributeName;
|
private final String attributeName;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String drawableName;
|
private final String drawableName;
|
||||||
|
|
||||||
|
HeaderLogo(String attributeName) {
|
||||||
|
this(Objects.requireNonNull(attributeName), Objects.requireNonNull(attributeName));
|
||||||
|
}
|
||||||
|
|
||||||
HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) {
|
HeaderLogo(@Nullable String attributeName, @Nullable String drawableName) {
|
||||||
this.attributeName = attributeName;
|
this.attributeName = attributeName;
|
||||||
this.drawableName = drawableName;
|
this.drawableName = drawableName;
|
||||||
@@ -42,9 +52,8 @@ public class ChangeHeaderPatch {
|
|||||||
|
|
||||||
final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
|
final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
|
||||||
if (identifier == 0) {
|
if (identifier == 0) {
|
||||||
// Identifier is zero if custom header setting was included in imported settings
|
// Should never happen.
|
||||||
// and a custom image was not included during patching.
|
Logger.printException(() -> "Could not find attribute: " + drawableName);
|
||||||
Logger.printDebug(() -> "Could not find attribute: " + drawableName);
|
|
||||||
Settings.HEADER_LOGO.resetToDefault();
|
Settings.HEADER_LOGO.resetToDefault();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -63,12 +72,14 @@ public class ChangeHeaderPatch {
|
|||||||
: "_light");
|
: "_light");
|
||||||
|
|
||||||
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
|
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
|
||||||
if (identifier == 0) {
|
if (identifier != 0) {
|
||||||
Logger.printDebug(() -> "Could not find drawable: " + drawableFullName);
|
return Utils.getContext().getDrawable(identifier);
|
||||||
Settings.HEADER_LOGO.resetToDefault();
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return Utils.getContext().getDrawable(identifier);
|
|
||||||
|
// Should never happen.
|
||||||
|
Logger.printException(() -> "Could not find drawable: " + drawableFullName);
|
||||||
|
Settings.HEADER_LOGO.resetToDefault();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +1,17 @@
|
|||||||
package app.revanced.extension.youtube.patches;
|
package app.revanced.extension.youtube.patches;
|
||||||
|
|
||||||
import app.revanced.extension.shared.Logger;
|
|
||||||
import app.revanced.extension.shared.settings.AppLanguage;
|
|
||||||
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
|
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class ForceOriginalAudioPatch {
|
public class ForceOriginalAudioPatch {
|
||||||
|
|
||||||
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static void setPreferredLanguage() {
|
public static void setEnabled() {
|
||||||
if (Settings.FORCE_ORIGINAL_AUDIO.get()
|
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
|
||||||
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()
|
Settings.FORCE_ORIGINAL_AUDIO.get(),
|
||||||
&& !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) {
|
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
|
||||||
// If client spoofing does not use authentication and lacks multi-audio streams,
|
);
|
||||||
// then can use any language code for the request and if that requested language is
|
|
||||||
// not available YT uses the original audio language. Authenticated requests ignore
|
|
||||||
// the language code and always use the account language. Use a language that is
|
|
||||||
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
|
|
||||||
// but the language is also supported natively by the Meta Quest device that
|
|
||||||
// Android VR is spoofing.
|
|
||||||
AppLanguage override = AppLanguage.SV;
|
|
||||||
Logger.printDebug(() -> "Setting language override: " + override);
|
|
||||||
SpoofVideoStreamsPatch.setLanguageOverride(override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection point.
|
|
||||||
*/
|
|
||||||
public static boolean ignoreDefaultAudioStream(boolean original) {
|
|
||||||
if (Settings.FORCE_ORIGINAL_AUDIO.get()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection point.
|
|
||||||
*/
|
|
||||||
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
|
|
||||||
try {
|
|
||||||
if (!Settings.FORCE_ORIGINAL_AUDIO.get()) {
|
|
||||||
return isDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audioTrackId.isEmpty()) {
|
|
||||||
// Older app targets can have empty audio tracks and these might be placeholders.
|
|
||||||
// The real audio tracks are called after these.
|
|
||||||
return isDefault;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
|
|
||||||
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
|
|
||||||
|
|
||||||
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
|
|
||||||
if (isOriginal) {
|
|
||||||
Logger.printDebug(() -> "Using audio: " + audioTrackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return isOriginal;
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Logger.printException(() -> "isDefaultAudioStream failure", ex);
|
|
||||||
return isDefault;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package app.revanced.extension.youtube.patches;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class HideEndScreenCardsPatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void hideEndScreenCardView(View view) {
|
||||||
|
Utils.hideViewUnderCondition(Settings.HIDE_ENDSCREEN_CARDS, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean hideEndScreenCards() {
|
||||||
|
return Settings.HIDE_ENDSCREEN_CARDS.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package app.revanced.extension.youtube.patches;
|
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
|
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class HideEndscreenCardsPatch {
|
|
||||||
//Used by app.revanced.patches.youtube.layout.hideendscreencards.bytecode.patch.HideEndscreenCardsPatch
|
|
||||||
public static void hideEndscreen(View view) {
|
|
||||||
if (!Settings.HIDE_ENDSCREEN_CARDS.get()) return;
|
|
||||||
view.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -131,11 +131,11 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
|
|
||||||
String conversionContextString = conversionContext.toString();
|
String conversionContextString = conversionContext.toString();
|
||||||
|
|
||||||
if (isRollingNumber && !conversionContextString.contains("video_action_bar.eml")) {
|
if (isRollingNumber && !conversionContextString.contains("video_action_bar.e")) {
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conversionContextString.contains("segmented_like_dislike_button.eml")) {
|
if (conversionContextString.contains("segmented_like_dislike_button.e")) {
|
||||||
// Regular video.
|
// Regular video.
|
||||||
ReturnYouTubeDislike videoData = currentVideoData;
|
ReturnYouTubeDislike videoData = currentVideoData;
|
||||||
if (videoData == null) {
|
if (videoData == null) {
|
||||||
@@ -153,12 +153,12 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.containsAny(conversionContextString,
|
if (Utils.containsAny(conversionContextString,
|
||||||
"|shorts_dislike_button.eml", "|reel_dislike_button.eml")) {
|
"|shorts_dislike_button.e", "|reel_dislike_button.e")) {
|
||||||
return getShortsSpan(original, true);
|
return getShortsSpan(original, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.containsAny(conversionContextString,
|
if (Utils.containsAny(conversionContextString,
|
||||||
"|shorts_like_button.eml", "|reel_like_button.eml")) {
|
"|shorts_like_button.e", "|reel_like_button.e")) {
|
||||||
if (!Utils.containsNumber(original)) {
|
if (!Utils.containsNumber(original)) {
|
||||||
Logger.printDebug(() -> "Replacing hidden likes count");
|
Logger.printDebug(() -> "Replacing hidden likes count");
|
||||||
return getShortsSpan(original, false);
|
return getShortsSpan(original, false);
|
||||||
|
|||||||
@@ -105,17 +105,17 @@ public final class AdsFilter extends Filter {
|
|||||||
Settings.HIDE_VIEW_PRODUCTS_BANNER,
|
Settings.HIDE_VIEW_PRODUCTS_BANNER,
|
||||||
"product_item",
|
"product_item",
|
||||||
"products_in_video",
|
"products_in_video",
|
||||||
"shopping_overlay.eml" // Video player overlay shopping links.
|
"shopping_overlay.e" // Video player overlay shopping links.
|
||||||
);
|
);
|
||||||
|
|
||||||
final var shoppingLinks = new StringFilterGroup(
|
final var shoppingLinks = new StringFilterGroup(
|
||||||
Settings.HIDE_SHOPPING_LINKS,
|
Settings.HIDE_SHOPPING_LINKS,
|
||||||
"shopping_description_shelf.eml"
|
"shopping_description_shelf.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
playerShoppingShelf = new StringFilterGroup(
|
playerShoppingShelf = new StringFilterGroup(
|
||||||
Settings.HIDE_CREATOR_STORE_SHELF,
|
Settings.HIDE_CREATOR_STORE_SHELF,
|
||||||
"horizontal_shelf.eml"
|
"horizontal_shelf.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
playerShoppingShelfBuffer = new ByteArrayFilterGroup(
|
playerShoppingShelfBuffer = new ByteArrayFilterGroup(
|
||||||
@@ -131,7 +131,7 @@ public final class AdsFilter extends Filter {
|
|||||||
final var merchandise = new StringFilterGroup(
|
final var merchandise = new StringFilterGroup(
|
||||||
Settings.HIDE_MERCHANDISE_BANNERS,
|
Settings.HIDE_MERCHANDISE_BANNERS,
|
||||||
"product_carousel",
|
"product_carousel",
|
||||||
"shopping_carousel.eml" // Channel profile shopping shelf.
|
"shopping_carousel.e" // Channel profile shopping shelf.
|
||||||
);
|
);
|
||||||
|
|
||||||
final var selfSponsor = new StringFilterGroup(
|
final var selfSponsor = new StringFilterGroup(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public final class AdvancedVideoQualityMenuFilter extends Filter {
|
|||||||
public AdvancedVideoQualityMenuFilter() {
|
public AdvancedVideoQualityMenuFilter() {
|
||||||
addPathCallbacks(new StringFilterGroup(
|
addPathCallbacks(new StringFilterGroup(
|
||||||
Settings.ADVANCED_VIDEO_QUALITY_MENU,
|
Settings.ADVANCED_VIDEO_QUALITY_MENU,
|
||||||
"quick_quality_sheet_content.eml-js"
|
"quick_quality_sheet_content.e"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import app.revanced.extension.youtube.settings.Settings;
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
final class ButtonsFilter extends Filter {
|
final class ButtonsFilter extends Filter {
|
||||||
private static final String COMPACT_CHANNEL_BAR_PATH_PREFIX = "compact_channel_bar.eml";
|
private static final String COMPACT_CHANNEL_BAR_PATH_PREFIX = "compact_channel_bar.e";
|
||||||
private static final String VIDEO_ACTION_BAR_PATH_PREFIX = "video_action_bar.eml";
|
private static final String VIDEO_ACTION_BAR_PATH_PREFIX = "video_action_bar.e";
|
||||||
private static final String VIDEO_ACTION_BAR_PATH = "video_action_bar.eml";
|
private static final String VIDEO_ACTION_BAR_PATH = "video_action_bar.e";
|
||||||
/**
|
/**
|
||||||
* Video bar path when the video information is collapsed. Seems to shown only with 20.14+
|
* Video bar path when the video information is collapsed. Seems to shown only with 20.14+
|
||||||
*/
|
*/
|
||||||
private static final String COMPACTIFY_VIDEO_ACTION_BAR_PATH = "compactify_video_action_bar.eml";
|
private static final String COMPACTIFY_VIDEO_ACTION_BAR_PATH = "compactify_video_action_bar.e";
|
||||||
private static final String ANIMATED_VECTOR_TYPE_PATH = "AnimatedVectorType";
|
private static final String ANIMATED_VECTOR_TYPE_PATH = "AnimatedVectorType";
|
||||||
|
|
||||||
private final StringFilterGroup likeSubscribeGlow;
|
private final StringFilterGroup likeSubscribeGlow;
|
||||||
@@ -28,12 +28,12 @@ final class ButtonsFilter extends Filter {
|
|||||||
|
|
||||||
likeSubscribeGlow = new StringFilterGroup(
|
likeSubscribeGlow = new StringFilterGroup(
|
||||||
Settings.DISABLE_LIKE_SUBSCRIBE_GLOW,
|
Settings.DISABLE_LIKE_SUBSCRIBE_GLOW,
|
||||||
"animated_button_border.eml"
|
"animated_button_border.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
bufferFilterPathGroup = new StringFilterGroup(
|
bufferFilterPathGroup = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"|ContainerType|button.eml"
|
"|ContainerType|button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
@@ -45,7 +45,7 @@ final class ButtonsFilter extends Filter {
|
|||||||
),
|
),
|
||||||
new StringFilterGroup(
|
new StringFilterGroup(
|
||||||
Settings.HIDE_DOWNLOAD_BUTTON,
|
Settings.HIDE_DOWNLOAD_BUTTON,
|
||||||
"|download_button.eml"
|
"|download_button.e"
|
||||||
),
|
),
|
||||||
new StringFilterGroup(
|
new StringFilterGroup(
|
||||||
Settings.HIDE_SAVE_BUTTON,
|
Settings.HIDE_SAVE_BUTTON,
|
||||||
@@ -53,7 +53,7 @@ final class ButtonsFilter extends Filter {
|
|||||||
),
|
),
|
||||||
new StringFilterGroup(
|
new StringFilterGroup(
|
||||||
Settings.HIDE_CLIP_BUTTON,
|
Settings.HIDE_CLIP_BUTTON,
|
||||||
"|clip_button.eml"
|
"|clip_button.e"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import app.revanced.extension.youtube.shared.PlayerType;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
final class CommentsFilter extends Filter {
|
final class CommentsFilter extends Filter {
|
||||||
|
|
||||||
private static final String COMMENT_COMPOSER_PATH = "comment_composer.eml";
|
private static final String COMMENT_COMPOSER_PATH = "comment_composer.e";
|
||||||
|
|
||||||
private final StringFilterGroup chipBar;
|
private final StringFilterGroup chipBar;
|
||||||
private final ByteArrayFilterGroup aiCommentsSummary;
|
private final ByteArrayFilterGroup aiCommentsSummary;
|
||||||
@@ -15,12 +15,12 @@ final class CommentsFilter extends Filter {
|
|||||||
public CommentsFilter() {
|
public CommentsFilter() {
|
||||||
var chatSummary = new StringFilterGroup(
|
var chatSummary = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
|
Settings.HIDE_COMMENTS_AI_CHAT_SUMMARY,
|
||||||
"live_chat_summary_banner.eml"
|
"live_chat_summary_banner.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
chipBar = new StringFilterGroup(
|
chipBar = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMENTS_AI_SUMMARY,
|
Settings.HIDE_COMMENTS_AI_SUMMARY,
|
||||||
"chip_bar.eml"
|
"chip_bar.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
aiCommentsSummary = new ByteArrayFilterGroup(
|
aiCommentsSummary = new ByteArrayFilterGroup(
|
||||||
@@ -35,8 +35,8 @@ final class CommentsFilter extends Filter {
|
|||||||
|
|
||||||
var commentsByMembers = new StringFilterGroup(
|
var commentsByMembers = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMENTS_BY_MEMBERS_HEADER,
|
Settings.HIDE_COMMENTS_BY_MEMBERS_HEADER,
|
||||||
"sponsorships_comments_header.eml",
|
"sponsorships_comments_header.e",
|
||||||
"sponsorships_comments_footer.eml"
|
"sponsorships_comments_footer.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
var comments = new StringFilterGroup(
|
var comments = new StringFilterGroup(
|
||||||
@@ -52,7 +52,7 @@ final class CommentsFilter extends Filter {
|
|||||||
|
|
||||||
var createAShort = new StringFilterGroup(
|
var createAShort = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMENTS_CREATE_A_SHORT_BUTTON,
|
Settings.HIDE_COMMENTS_CREATE_A_SHORT_BUTTON,
|
||||||
"composer_short_creation_button.eml"
|
"composer_short_creation_button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
emojiAndTimestampButtons = new StringFilterGroup(
|
emojiAndTimestampButtons = new StringFilterGroup(
|
||||||
@@ -69,7 +69,7 @@ final class CommentsFilter extends Filter {
|
|||||||
|
|
||||||
var thanksButton = new StringFilterGroup(
|
var thanksButton = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMENTS_THANKS_BUTTON,
|
Settings.HIDE_COMMENTS_THANKS_BUTTON,
|
||||||
"super_thanks_button.eml"
|
"super_thanks_button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ final class DescriptionComponentsFilter extends Filter {
|
|||||||
|
|
||||||
aiGeneratedVideoSummarySection = new StringFilterGroup(
|
aiGeneratedVideoSummarySection = new StringFilterGroup(
|
||||||
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
|
Settings.HIDE_AI_GENERATED_VIDEO_SUMMARY_SECTION,
|
||||||
"cell_expandable_metadata.eml"
|
"cell_expandable_metadata.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
final StringFilterGroup askSection = new StringFilterGroup(
|
final StringFilterGroup askSection = new StringFilterGroup(
|
||||||
Settings.HIDE_ASK_SECTION,
|
Settings.HIDE_ASK_SECTION,
|
||||||
"youchat_entrypoint.eml"
|
"youchat_entrypoint.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
final StringFilterGroup attributesSection = new StringFilterGroup(
|
final StringFilterGroup attributesSection = new StringFilterGroup(
|
||||||
@@ -65,7 +65,7 @@ final class DescriptionComponentsFilter extends Filter {
|
|||||||
|
|
||||||
macroMarkersCarousel = new StringFilterGroup(
|
macroMarkersCarousel = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"macro_markers_carousel.eml"
|
"macro_markers_carousel.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
macroMarkersCarouselGroupList.addAll(
|
macroMarkersCarouselGroupList.addAll(
|
||||||
@@ -81,7 +81,7 @@ final class DescriptionComponentsFilter extends Filter {
|
|||||||
|
|
||||||
horizontalShelf = new StringFilterGroup(
|
horizontalShelf = new StringFilterGroup(
|
||||||
Settings.HIDE_ATTRIBUTES_SECTION,
|
Settings.HIDE_ATTRIBUTES_SECTION,
|
||||||
"horizontal_shelf.eml"
|
"horizontal_shelf.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
cellVideoAttribute = new ByteArrayFilterGroup(
|
cellVideoAttribute = new ByteArrayFilterGroup(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public final class HideInfoCardsFilter extends Filter {
|
|||||||
addIdentifierCallbacks(
|
addIdentifierCallbacks(
|
||||||
new StringFilterGroup(
|
new StringFilterGroup(
|
||||||
Settings.HIDE_INFO_CARDS,
|
Settings.HIDE_INFO_CARDS,
|
||||||
"info_card_teaser_overlay.eml"
|
"info_card_teaser_overlay.e"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ final class KeywordContentFilter extends Filter {
|
|||||||
"search_vwc_description_transition_key",
|
"search_vwc_description_transition_key",
|
||||||
"g-high-recZ",
|
"g-high-recZ",
|
||||||
// Text and litho components found in the buffer that belong to path filters.
|
// Text and litho components found in the buffer that belong to path filters.
|
||||||
"expandable_metadata.eml",
|
"expandable_metadata.e",
|
||||||
"thumbnail.eml",
|
"thumbnail.e",
|
||||||
"avatar.eml",
|
"avatar.e",
|
||||||
"overflow_button.eml",
|
"overflow_button.e",
|
||||||
"shorts-lockup-image",
|
"shorts-lockup-image",
|
||||||
"shorts-lockup.overlay-metadata.secondary-text",
|
"shorts-lockup.overlay-metadata.secondary-text",
|
||||||
"YouTubeSans-SemiBold",
|
"YouTubeSans-SemiBold",
|
||||||
@@ -94,16 +94,16 @@ final class KeywordContentFilter extends Filter {
|
|||||||
*/
|
*/
|
||||||
private final StringFilterGroup startsWithFilter = new StringFilterGroup(
|
private final StringFilterGroup startsWithFilter = new StringFilterGroup(
|
||||||
null, // Multiple settings are used and must be individually checked if active.
|
null, // Multiple settings are used and must be individually checked if active.
|
||||||
"home_video_with_context.eml",
|
"home_video_with_context.e",
|
||||||
"search_video_with_context.eml",
|
"search_video_with_context.e",
|
||||||
"video_with_context.eml", // Subscription tab videos.
|
"video_with_context.e", // Subscription tab videos.
|
||||||
"related_video_with_context.eml",
|
"related_video_with_context.e",
|
||||||
// A/B test for subscribed video, and sometimes when tablet layout is enabled.
|
// A/B test for subscribed video, and sometimes when tablet layout is enabled.
|
||||||
"video_lockup_with_attachment.eml",
|
"video_lockup_with_attachment.e",
|
||||||
"compact_video.eml",
|
"compact_video.e",
|
||||||
"inline_shorts",
|
"inline_shorts",
|
||||||
"shorts_video_cell",
|
"shorts_video_cell",
|
||||||
"shorts_pivot_item.eml"
|
"shorts_pivot_item.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,9 +112,9 @@ final class KeywordContentFilter extends Filter {
|
|||||||
@SuppressWarnings("FieldCanBeLocal")
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
private final StringFilterGroup containsFilter = new StringFilterGroup(
|
private final StringFilterGroup containsFilter = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"modern_type_shelf_header_content.eml",
|
"modern_type_shelf_header_content.e",
|
||||||
"shorts_lockup_cell.eml", // Part of 'shorts_shelf_carousel.eml'
|
"shorts_lockup_cell.e", // Part of 'shorts_shelf_carousel.e'
|
||||||
"video_card.eml" // Shorts that appear in a horizontal shelf.
|
"video_card.e" // Shorts that appear in a horizontal shelf.
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,10 +125,10 @@ final class KeywordContentFilter extends Filter {
|
|||||||
* the buffer of the parent component was already searched and passed.
|
* the buffer of the parent component was already searched and passed.
|
||||||
*/
|
*/
|
||||||
private final StringTrieSearch exceptions = new StringTrieSearch(
|
private final StringTrieSearch exceptions = new StringTrieSearch(
|
||||||
"metadata.eml",
|
"metadata.e",
|
||||||
"thumbnail.eml",
|
"thumbnail.e",
|
||||||
"avatar.eml",
|
"avatar.e",
|
||||||
"overflow_button.eml"
|
"overflow_button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -76,18 +76,19 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
communityPosts = new StringFilterGroup(
|
communityPosts = new StringFilterGroup(
|
||||||
Settings.HIDE_COMMUNITY_POSTS,
|
Settings.HIDE_COMMUNITY_POSTS,
|
||||||
"post_base_wrapper", // may be obsolete and no longer needed.
|
"post_base_wrapper", // may be obsolete and no longer needed.
|
||||||
"text_post_root.eml",
|
"text_post_root.e",
|
||||||
"images_post_root.eml",
|
"images_post_root.e",
|
||||||
"images_post_slim.eml", // may be obsolete and no longer needed.
|
"images_post_slim.e", // may be obsolete and no longer needed.
|
||||||
"images_post_root_slim.eml",
|
"images_post_root_slim.e",
|
||||||
"text_post_root_slim.eml",
|
"text_post_root_slim.e",
|
||||||
"post_base_wrapper_slim.eml",
|
"post_base_wrapper_slim.e",
|
||||||
"poll_post_root.eml",
|
"poll_post_root.e",
|
||||||
"videos_post_root.eml",
|
"videos_post_root.e",
|
||||||
"post_shelf_slim.eml",
|
"post_shelf_slim.e",
|
||||||
"videos_post_responsive_root.eml",
|
"videos_post_responsive_root.e",
|
||||||
"text_post_responsive_root.eml",
|
"text_post_responsive_root.e",
|
||||||
"poll_post_responsive_root.eml"
|
"poll_post_responsive_root.e",
|
||||||
|
"shared_post_root.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
final var subscribersCommunityGuidelines = new StringFilterGroup(
|
final var subscribersCommunityGuidelines = new StringFilterGroup(
|
||||||
@@ -149,7 +150,7 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
|
|
||||||
final var channelLinksPreview = new StringFilterGroup(
|
final var channelLinksPreview = new StringFilterGroup(
|
||||||
Settings.HIDE_LINKS_PREVIEW,
|
Settings.HIDE_LINKS_PREVIEW,
|
||||||
"attribution.eml"
|
"attribution.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
final var emergencyBox = new StringFilterGroup(
|
final var emergencyBox = new StringFilterGroup(
|
||||||
@@ -190,8 +191,8 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
|
|
||||||
final var playables = new StringFilterGroup(
|
final var playables = new StringFilterGroup(
|
||||||
Settings.HIDE_PLAYABLES,
|
Settings.HIDE_PLAYABLES,
|
||||||
"horizontal_gaming_shelf.eml",
|
"horizontal_gaming_shelf.e",
|
||||||
"mini_game_card.eml"
|
"mini_game_card.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Playable horizontal shelf header.
|
// Playable horizontal shelf header.
|
||||||
@@ -228,7 +229,7 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
|
|
||||||
compactChannelBarInnerButton = new StringFilterGroup(
|
compactChannelBarInnerButton = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"|button.eml"
|
"|button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
joinMembershipButton = new ByteArrayFilterGroup(
|
joinMembershipButton = new ByteArrayFilterGroup(
|
||||||
@@ -248,13 +249,13 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
|
|
||||||
final var videoRecommendationLabels = new StringFilterGroup(
|
final var videoRecommendationLabels = new StringFilterGroup(
|
||||||
Settings.HIDE_VIDEO_RECOMMENDATION_LABELS,
|
Settings.HIDE_VIDEO_RECOMMENDATION_LABELS,
|
||||||
"endorsement_header_footer.eml"
|
"endorsement_header_footer.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
channelProfile = new StringFilterGroup(
|
channelProfile = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"channel_profile.eml",
|
"channel_profile.e",
|
||||||
"page_header.eml"
|
"page_header.e"
|
||||||
);
|
);
|
||||||
channelProfileBuffer = new ByteArrayFilterGroupList();
|
channelProfileBuffer = new ByteArrayFilterGroupList();
|
||||||
channelProfileBuffer.addAll(new ByteArrayFilterGroup(
|
channelProfileBuffer.addAll(new ByteArrayFilterGroup(
|
||||||
@@ -269,15 +270,15 @@ public final class LayoutComponentsFilter extends Filter {
|
|||||||
|
|
||||||
horizontalShelves = new StringFilterGroup(
|
horizontalShelves = new StringFilterGroup(
|
||||||
Settings.HIDE_HORIZONTAL_SHELVES,
|
Settings.HIDE_HORIZONTAL_SHELVES,
|
||||||
"horizontal_video_shelf.eml",
|
"horizontal_video_shelf.e",
|
||||||
"horizontal_shelf.eml",
|
"horizontal_shelf.e",
|
||||||
"horizontal_shelf_inline.eml",
|
"horizontal_shelf_inline.e",
|
||||||
"horizontal_tile_shelf.eml"
|
"horizontal_tile_shelf.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
ticketShelf = new ByteArrayFilterGroup(
|
ticketShelf = new ByteArrayFilterGroup(
|
||||||
Settings.HIDE_TICKET_SHELF,
|
Settings.HIDE_TICKET_SHELF,
|
||||||
"ticket_item.eml"
|
"ticket_item.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ public final class PlaybackSpeedMenuFilter extends Filter {
|
|||||||
// 0.05x litho speed menu.
|
// 0.05x litho speed menu.
|
||||||
var playbackRateSelectorGroup = new StringFilterGroup(
|
var playbackRateSelectorGroup = new StringFilterGroup(
|
||||||
Settings.CUSTOM_SPEED_MENU,
|
Settings.CUSTOM_SPEED_MENU,
|
||||||
"playback_rate_selector_menu_sheet.eml-js"
|
"playback_rate_selector_menu_sheet.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Old litho based speed menu.
|
// Old litho based speed menu.
|
||||||
oldPlaybackMenuGroup = new StringFilterGroup(
|
oldPlaybackMenuGroup = new StringFilterGroup(
|
||||||
Settings.CUSTOM_SPEED_MENU,
|
Settings.CUSTOM_SPEED_MENU,
|
||||||
"playback_speed_sheet_content.eml-js");
|
"playback_speed_sheet_content.e");
|
||||||
|
|
||||||
addPathCallbacks(playbackRateSelectorGroup, oldPlaybackMenuGroup);
|
addPathCallbacks(playbackRateSelectorGroup, oldPlaybackMenuGroup);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class PlayerFlyoutMenuItemsFilter extends Filter {
|
|||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
videoQualityMenuFooter,
|
videoQualityMenuFooter,
|
||||||
new StringFilterGroup(null, "overflow_menu_item.eml")
|
new StringFilterGroup(null, "overflow_menu_item.e")
|
||||||
);
|
);
|
||||||
|
|
||||||
flyoutFilterGroupList.addAll(
|
flyoutFilterGroupList.addAll(
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ public final class ReturnYouTubeDislikeFilter extends Filter {
|
|||||||
// But if swiping back to a previous video and liking/disliking, then only that single button reloads.
|
// But if swiping back to a previous video and liking/disliking, then only that single button reloads.
|
||||||
// So must check for both buttons.
|
// So must check for both buttons.
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
new StringFilterGroup(null, "|shorts_like_button.eml"),
|
new StringFilterGroup(null, "|shorts_like_button.e"),
|
||||||
new StringFilterGroup(null, "|shorts_dislike_button.eml")
|
new StringFilterGroup(null, "|shorts_dislike_button.e")
|
||||||
);
|
);
|
||||||
|
|
||||||
// After the button identifiers is binary data and then the video id for that specific short.
|
// After the button identifiers is binary data and then the video id for that specific short.
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ import app.revanced.extension.youtube.shared.PlayerType;
|
|||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class ShortsFilter extends Filter {
|
public final class ShortsFilter extends Filter {
|
||||||
private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get();
|
private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get();
|
||||||
private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.eml";
|
private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.e";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For paid promotion label and subscribe button that appears in the channel bar.
|
* For paid promotion label and subscribe button that appears in the channel bar.
|
||||||
*/
|
*/
|
||||||
private static final String REEL_METAPANEL_PATH = "reel_metapanel.eml";
|
private static final String REEL_METAPANEL_PATH = "reel_metapanel.e";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tags that appears when opening the Shorts player.
|
* Tags that appears when opening the Shorts player.
|
||||||
@@ -74,7 +74,7 @@ public final class ShortsFilter extends Filter {
|
|||||||
// Use a different filter group for this pattern, as it requires an additional check after matching.
|
// Use a different filter group for this pattern, as it requires an additional check after matching.
|
||||||
shelfHeader = new StringFilterGroup(
|
shelfHeader = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"shelf_header.eml"
|
"shelf_header.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
addIdentifierCallbacks(shortsIdentifiers, shelfHeader);
|
addIdentifierCallbacks(shortsIdentifiers, shelfHeader);
|
||||||
@@ -85,11 +85,11 @@ public final class ShortsFilter extends Filter {
|
|||||||
|
|
||||||
shortsCompactFeedVideo = new StringFilterGroup(null,
|
shortsCompactFeedVideo = new StringFilterGroup(null,
|
||||||
// Shorts that appear in the feed/search when the device is using tablet layout.
|
// Shorts that appear in the feed/search when the device is using tablet layout.
|
||||||
"compact_video.eml",
|
"compact_video.e",
|
||||||
// 'video_lockup_with_attachment.eml' is shown instead of 'compact_video.eml' for some users
|
// 'video_lockup_with_attachment.e' is shown instead of 'compact_video.e' for some users
|
||||||
"video_lockup_with_attachment.eml",
|
"video_lockup_with_attachment.e",
|
||||||
// Search results that appear in a horizontal shelf.
|
// Search results that appear in a horizontal shelf.
|
||||||
"video_card.eml");
|
"video_card.e");
|
||||||
|
|
||||||
// Filter out items that use the 'frame0' thumbnail.
|
// Filter out items that use the 'frame0' thumbnail.
|
||||||
// This is a valid thumbnail for both regular videos and Shorts,
|
// This is a valid thumbnail for both regular videos and Shorts,
|
||||||
@@ -134,31 +134,31 @@ public final class ShortsFilter extends Filter {
|
|||||||
|
|
||||||
StringFilterGroup stickers = new StringFilterGroup(
|
StringFilterGroup stickers = new StringFilterGroup(
|
||||||
Settings.HIDE_SHORTS_STICKERS,
|
Settings.HIDE_SHORTS_STICKERS,
|
||||||
"stickers_layer.eml"
|
"stickers_layer.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
StringFilterGroup likeFountain = new StringFilterGroup(
|
StringFilterGroup likeFountain = new StringFilterGroup(
|
||||||
Settings.HIDE_SHORTS_LIKE_FOUNTAIN,
|
Settings.HIDE_SHORTS_LIKE_FOUNTAIN,
|
||||||
"like_fountain.eml"
|
"like_fountain.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
StringFilterGroup likeButton = new StringFilterGroup(
|
StringFilterGroup likeButton = new StringFilterGroup(
|
||||||
Settings.HIDE_SHORTS_LIKE_BUTTON,
|
Settings.HIDE_SHORTS_LIKE_BUTTON,
|
||||||
"shorts_like_button.eml",
|
"shorts_like_button.e",
|
||||||
"reel_like_button.eml"
|
"reel_like_button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
StringFilterGroup dislikeButton = new StringFilterGroup(
|
StringFilterGroup dislikeButton = new StringFilterGroup(
|
||||||
Settings.HIDE_SHORTS_DISLIKE_BUTTON,
|
Settings.HIDE_SHORTS_DISLIKE_BUTTON,
|
||||||
"shorts_dislike_button.eml",
|
"shorts_dislike_button.e",
|
||||||
"reel_dislike_button.eml"
|
"reel_dislike_button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
StringFilterGroup previewComment = new StringFilterGroup(
|
StringFilterGroup previewComment = new StringFilterGroup(
|
||||||
Settings.HIDE_SHORTS_PREVIEW_COMMENT,
|
Settings.HIDE_SHORTS_PREVIEW_COMMENT,
|
||||||
// Preview comment that can popup while a Short is playing.
|
// Preview comment that can popup while a Short is playing.
|
||||||
// Uses no bundled icons, and instead the users profile photo is shown.
|
// Uses no bundled icons, and instead the users profile photo is shown.
|
||||||
"participation_bar.eml"
|
"participation_bar.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
joinButton = new StringFilterGroup(
|
joinButton = new StringFilterGroup(
|
||||||
@@ -173,20 +173,20 @@ public final class ShortsFilter extends Filter {
|
|||||||
|
|
||||||
paidPromotionButton = new StringFilterGroup(
|
paidPromotionButton = new StringFilterGroup(
|
||||||
Settings.HIDE_PAID_PROMOTION_LABEL,
|
Settings.HIDE_PAID_PROMOTION_LABEL,
|
||||||
"reel_player_disclosure.eml"
|
"reel_player_disclosure.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
shortsActionBar = new StringFilterGroup(
|
shortsActionBar = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"shorts_action_bar.eml",
|
"shorts_action_bar.e",
|
||||||
"reel_action_bar.eml"
|
"reel_action_bar.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
useSoundButton = new StringFilterGroup(
|
useSoundButton = new StringFilterGroup(
|
||||||
Settings.HIDE_SHORTS_USE_SOUND_BUTTON,
|
Settings.HIDE_SHORTS_USE_SOUND_BUTTON,
|
||||||
// First filter needed for "Use this sound" that can appear when viewing Shorts
|
// First filter needed for "Use this sound" that can appear when viewing Shorts
|
||||||
// through the "Short remixing this video" section.
|
// through the "Short remixing this video" section.
|
||||||
"floating_action_button.eml",
|
"floating_action_button.e",
|
||||||
// Second filter needed for "Use this sound" that can appear below the video title.
|
// Second filter needed for "Use this sound" that can appear below the video title.
|
||||||
REEL_METAPANEL_PATH
|
REEL_METAPANEL_PATH
|
||||||
);
|
);
|
||||||
@@ -209,13 +209,13 @@ public final class ShortsFilter extends Filter {
|
|||||||
|
|
||||||
videoActionButton = new StringFilterGroup(
|
videoActionButton = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
// Can be simply 'button.eml', 'shorts_video_action_button.eml' or 'reel_action_button.eml'
|
// Can be simply 'button.e', 'shorts_video_action_button.e' or 'reel_action_button.e'
|
||||||
"button.eml"
|
"button.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
suggestedAction = new StringFilterGroup(
|
suggestedAction = new StringFilterGroup(
|
||||||
null,
|
null,
|
||||||
"suggested_action.eml"
|
"suggested_action.e"
|
||||||
);
|
);
|
||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
|
|||||||
@@ -8,38 +8,40 @@ import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.settings.Setting;
|
||||||
import app.revanced.extension.shared.spoof.ClientType;
|
import app.revanced.extension.shared.spoof.ClientType;
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class SpoofVideoStreamsPatch {
|
public class SpoofVideoStreamsPatch {
|
||||||
|
|
||||||
|
public static final class SpoofClientAv1Availability implements Setting.Availability {
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.isAvailable()
|
||||||
|
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ANDROID_VR_1_43_32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static void setClientOrderToUse() {
|
public static void setClientOrderToUse() {
|
||||||
final boolean forceAVC = Settings.FORCE_AVC_CODEC.get();
|
|
||||||
|
|
||||||
// VR 1.61 uses VP9/AV1, and cannot force AVC.
|
|
||||||
ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
|
||||||
if (forceAVC && client == ANDROID_VR_1_61_48) {
|
|
||||||
client = ANDROID_VR_1_43_32; // Use VR 1.43 instead.
|
// Use VR 1.61 client that has AV1 if user settings allow it.
|
||||||
|
// AVC cannot be forced with VR 1.61 because it uses VP9 and AV1.
|
||||||
|
// If both settings are on, then force AVC takes priority and VR 1.43 is used.
|
||||||
|
if (client == ANDROID_VR_1_43_32 && Settings.SPOOF_VIDEO_STREAMS_AV1.get()
|
||||||
|
&& !Settings.FORCE_AVC_CODEC.get()) {
|
||||||
|
client = ANDROID_VR_1_61_48;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ClientType> availableClients = forceAVC
|
List<ClientType> availableClients = List.of(
|
||||||
? List.of(
|
|
||||||
ANDROID_VR_1_43_32,
|
|
||||||
VISIONOS,
|
|
||||||
ANDROID_CREATOR,
|
|
||||||
ANDROID_VR_1_61_48,
|
|
||||||
IPADOS)
|
|
||||||
: List.of(
|
|
||||||
ANDROID_VR_1_61_48,
|
|
||||||
VISIONOS,
|
VISIONOS,
|
||||||
ANDROID_CREATOR,
|
ANDROID_CREATOR,
|
||||||
ANDROID_VR_1_43_32,
|
ANDROID_VR_1_43_32,
|
||||||
IPADOS
|
IPADOS);
|
||||||
);
|
|
||||||
|
|
||||||
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
|
||||||
availableClients, client);
|
availableClients, client);
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
package app.revanced.extension.youtube.patches.theme;
|
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.ColorFilter;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import app.revanced.extension.youtube.patches.HideSeekbarPatch;
|
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by {@link SeekbarColorPatch} change the color of the seekbar.
|
|
||||||
* and {@link HideSeekbarPatch} to hide the seekbar of the feed and watch history.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public class ProgressBarDrawable extends Drawable {
|
|
||||||
|
|
||||||
private final Paint paint = new Paint();
|
|
||||||
{
|
|
||||||
paint.setColor(SeekbarColorPatch.getSeekbarColor());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void draw(@NonNull Canvas canvas) {
|
|
||||||
if (Settings.HIDE_SEEKBAR_THUMBNAIL.get()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.drawRect(getBounds(), paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAlpha(int alpha) {
|
|
||||||
paint.setAlpha(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
|
||||||
paint.setColorFilter(colorFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOpacity() {
|
|
||||||
return PixelFormat.TRANSLUCENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -4,9 +4,7 @@ import static app.revanced.extension.shared.StringRef.str;
|
|||||||
import static app.revanced.extension.shared.Utils.clamp;
|
import static app.revanced.extension.shared.Utils.clamp;
|
||||||
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
|
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
|
||||||
|
|
||||||
import com.airbnb.lottie.LottieAnimationView;
|
import com.airbnb.lottie.LottieAnimationView;
|
||||||
|
|
||||||
@@ -15,7 +13,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
import app.revanced.extension.shared.Logger;
|
import app.revanced.extension.shared.Logger;
|
||||||
@@ -104,27 +101,6 @@ public final class SeekbarColorPatch {
|
|||||||
return customSeekbarColor;
|
return customSeekbarColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int colorChannelTo3Bits(int channel8Bits) {
|
|
||||||
final float channel3Bits = channel8Bits * 7 / 255f;
|
|
||||||
|
|
||||||
// If a color channel is near zero, then allow rounding up so values between
|
|
||||||
// 0x12 and 0x23 will show as 0x24. But always round down when the channel is
|
|
||||||
// near full saturation, otherwise rounding to nearest will cause all values
|
|
||||||
// between 0xEC and 0xFE to always show as full saturation (0xFF).
|
|
||||||
return channel3Bits < 6
|
|
||||||
? Math.round(channel3Bits)
|
|
||||||
: (int) channel3Bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("SameParameterValue")
|
|
||||||
private static String get9BitStyleIdentifier(int color24Bit) {
|
|
||||||
final int r3 = colorChannelTo3Bits(Color.red(color24Bit));
|
|
||||||
final int g3 = colorChannelTo3Bits(Color.green(color24Bit));
|
|
||||||
final int b3 = colorChannelTo3Bits(Color.blue(color24Bit));
|
|
||||||
|
|
||||||
return String.format(Locale.US, "splash_seekbar_color_style_%d_%d_%d", r3, g3, b3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* injection point.
|
* injection point.
|
||||||
*/
|
*/
|
||||||
@@ -135,36 +111,6 @@ public final class SeekbarColorPatch {
|
|||||||
return original; // false = drawable style, true = lottie style.
|
return original; // false = drawable style, true = lottie style.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Injection point.
|
|
||||||
* Old drawable style launch screen.
|
|
||||||
*/
|
|
||||||
public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vectorDrawable) {
|
|
||||||
// Alternatively a ColorMatrixColorFilter can be used to change the color of the drawable
|
|
||||||
// without using any styles, but a color filter cannot selectively change the seekbar
|
|
||||||
// while keeping the red YT logo untouched.
|
|
||||||
// Even if the seekbar color xml value is changed to a completely different color (such as green),
|
|
||||||
// a color filter still cannot be selectively applied when the drawable has more than 1 color.
|
|
||||||
try {
|
|
||||||
// Must set the color even if custom seekbar is off,
|
|
||||||
// because the xml color was replaced with a themed value.
|
|
||||||
String seekbarStyle = get9BitStyleIdentifier(customSeekbarColor);
|
|
||||||
Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle);
|
|
||||||
|
|
||||||
final int styleIdentifierDefault = Utils.getResourceIdentifierOrThrow(
|
|
||||||
seekbarStyle,
|
|
||||||
"style"
|
|
||||||
);
|
|
||||||
|
|
||||||
Resources.Theme theme = Utils.getContext().getResources().newTheme();
|
|
||||||
theme.applyStyle(styleIdentifierDefault, true);
|
|
||||||
|
|
||||||
vectorDrawable.applyTheme(theme);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Logger.printException(() -> "setSplashAnimationDrawableTheme failure", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
* Modern Lottie style animation.
|
* Modern Lottie style animation.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package app.revanced.extension.youtube.settings;
|
|||||||
|
|
||||||
import static java.lang.Boolean.FALSE;
|
import static java.lang.Boolean.FALSE;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
import static app.revanced.extension.shared.settings.Setting.migrateOldSettingToNew;
|
|
||||||
import static app.revanced.extension.shared.settings.Setting.parent;
|
import static app.revanced.extension.shared.settings.Setting.parent;
|
||||||
import static app.revanced.extension.shared.settings.Setting.parentsAll;
|
import static app.revanced.extension.shared.settings.Setting.parentsAll;
|
||||||
import static app.revanced.extension.shared.settings.Setting.parentsAny;
|
import static app.revanced.extension.shared.settings.Setting.parentsAny;
|
||||||
@@ -17,10 +16,10 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerH
|
|||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideSubtextsAvailability;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHideSubtextsAvailability;
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerHorizontalDragAvailability;
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
|
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
|
||||||
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.MINIMAL;
|
|
||||||
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
|
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
|
||||||
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
|
||||||
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
|
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
|
||||||
|
import static app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch.SpoofClientAv1Availability;
|
||||||
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
|
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
|
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
|
||||||
@@ -40,7 +39,6 @@ import app.revanced.extension.shared.settings.IntegerSetting;
|
|||||||
import app.revanced.extension.shared.settings.LongSetting;
|
import app.revanced.extension.shared.settings.LongSetting;
|
||||||
import app.revanced.extension.shared.settings.Setting;
|
import app.revanced.extension.shared.settings.Setting;
|
||||||
import app.revanced.extension.shared.settings.StringSetting;
|
import app.revanced.extension.shared.settings.StringSetting;
|
||||||
import app.revanced.extension.shared.settings.preference.SharedPrefCategory;
|
|
||||||
import app.revanced.extension.shared.spoof.ClientType;
|
import app.revanced.extension.shared.spoof.ClientType;
|
||||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
|
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrowAvailability;
|
||||||
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
|
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
|
||||||
@@ -55,6 +53,7 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
|
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
|
||||||
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
|
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
|
||||||
public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message");
|
public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message");
|
||||||
|
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
|
||||||
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
|
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
|
||||||
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
|
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
|
||||||
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
|
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
|
||||||
@@ -75,9 +74,6 @@ public class Settings extends BaseSettings {
|
|||||||
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
|
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
|
||||||
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);
|
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);
|
||||||
|
|
||||||
// Audio
|
|
||||||
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
|
|
||||||
|
|
||||||
// Ads
|
// Ads
|
||||||
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
|
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
|
||||||
public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true);
|
public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true);
|
||||||
@@ -358,7 +354,9 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting EXTERNAL_BROWSER = new BooleanSetting("revanced_external_browser", TRUE, true);
|
public static final BooleanSetting EXTERNAL_BROWSER = new BooleanSetting("revanced_external_browser", TRUE, true);
|
||||||
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
|
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
|
||||||
"revanced_spoof_device_dimensions_user_dialog_message");
|
"revanced_spoof_device_dimensions_user_dialog_message");
|
||||||
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS));
|
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
|
||||||
|
public static final BooleanSetting SPOOF_VIDEO_STREAMS_AV1 = new BooleanSetting("revanced_spoof_video_streams_av1", FALSE, true,
|
||||||
|
"revanced_spoof_video_streams_av1_user_dialog_message", new SpoofClientAv1Availability());
|
||||||
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
|
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
|
||||||
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
|
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
|
||||||
|
|
||||||
@@ -451,14 +449,7 @@ public class Settings extends BaseSettings {
|
|||||||
public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFFFF", false, false);
|
public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFFFF", false, false);
|
||||||
|
|
||||||
// Deprecated migrations
|
// Deprecated migrations
|
||||||
private static final BooleanSetting DEPRECATED_AUTO_REPEAT = new BooleanSetting("revanced_auto_repeat", FALSE);
|
|
||||||
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true);
|
|
||||||
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE);
|
|
||||||
private static final IntegerSetting DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA = new IntegerSetting("revanced_swipe_overlay_background_alpha", 127);
|
|
||||||
private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033");
|
private static final StringSetting DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY = new StringSetting("revanced_seekbar_custom_color_value", "#FF0033");
|
||||||
private static final BooleanSetting DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN = new BooleanSetting("revanced_disable_suggested_video_end_screen", FALSE);
|
|
||||||
private static final BooleanSetting DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
|
|
||||||
private static final BooleanSetting DEPRECATED_AUTO_CAPTIONS = new BooleanSetting("revanced_auto_captions", FALSE);
|
|
||||||
|
|
||||||
private static final FloatSetting DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f, false, false);
|
private static final FloatSetting DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f, false, false);
|
||||||
private static final FloatSetting DEPRECATED_SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f, false, false);
|
private static final FloatSetting DEPRECATED_SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f, false, false);
|
||||||
@@ -474,17 +465,12 @@ public class Settings extends BaseSettings {
|
|||||||
static {
|
static {
|
||||||
// region Migration
|
// region Migration
|
||||||
|
|
||||||
migrateOldSettingToNew(DEPRECATED_AUTO_REPEAT, LOOP_VIDEO);
|
// Migrate renamed change header enums.
|
||||||
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS);
|
if (HEADER_LOGO.get() == HeaderLogo.REVANCED) {
|
||||||
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER);
|
HEADER_LOGO.save(HeaderLogo.ROUNDED);
|
||||||
migrateOldSettingToNew(DEPRECATED_DISABLE_SUGGESTED_VIDEO_END_SCREEN, HIDE_END_SCREEN_SUGGESTED_VIDEO);
|
}
|
||||||
migrateOldSettingToNew(DEPRECATED_RESTORE_OLD_VIDEO_QUALITY_MENU, ADVANCED_VIDEO_QUALITY_MENU);
|
if (HEADER_LOGO.get() == HeaderLogo.REVANCED_MINIMAL) {
|
||||||
migrateOldSettingToNew(DEPRECATED_AUTO_CAPTIONS, DISABLE_AUTO_CAPTIONS);
|
HEADER_LOGO.save(HeaderLogo.MINIMAL);
|
||||||
|
|
||||||
// Migrate renamed enum.
|
|
||||||
//noinspection deprecation
|
|
||||||
if (MINIPLAYER_TYPE.get() == MiniplayerType.PHONE) {
|
|
||||||
MINIPLAYER_TYPE.save(MINIMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate old single color seekbar with a slightly brighter accent color based on the primary.
|
// Migrate old single color seekbar with a slightly brighter accent color based on the primary.
|
||||||
@@ -511,11 +497,6 @@ public class Settings extends BaseSettings {
|
|||||||
DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY.resetToDefault();
|
DEPRECATED_SEEKBAR_CUSTOM_COLOR_PRIMARY.resetToDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.isSetToDefault()) {
|
|
||||||
SWIPE_OVERLAY_OPACITY.save(DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.get() / 255);
|
|
||||||
DEPRECATED_SWIPE_OVERLAY_BACKGROUND_ALPHA.resetToDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Old spoof versions that no longer work,
|
// Old spoof versions that no longer work,
|
||||||
// or is spoofing to a version the same or newer than this app.
|
// or is spoofing to a version the same or newer than this app.
|
||||||
if (!SPOOF_APP_VERSION_TARGET.isSetToDefault() &&
|
if (!SPOOF_APP_VERSION_TARGET.isSetToDefault() &&
|
||||||
@@ -526,15 +507,14 @@ public class Settings extends BaseSettings {
|
|||||||
SPOOF_APP_VERSION.resetToDefault();
|
SPOOF_APP_VERSION.resetToDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VR 1.61 is not selectable in the settings, and it's selected by spoof stream patch if needed.
|
||||||
|
if (SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_1_61_48) {
|
||||||
|
SPOOF_VIDEO_STREAMS_CLIENT_TYPE.resetToDefault();
|
||||||
|
}
|
||||||
|
|
||||||
// RYD requires manually migrating old settings since the lack of
|
// RYD requires manually migrating old settings since the lack of
|
||||||
// a "revanced_" on the old setting causes duplicate key exceptions during export.
|
// a "revanced_" on the old setting causes duplicate key exceptions during export.
|
||||||
SharedPrefCategory revancedPrefs = Setting.preferences;
|
Setting.migrateFromOldPreferences(Setting.preferences, RYD_USER_ID, "ryd_user_id");
|
||||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_USER_ID, "ryd_user_id");
|
|
||||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_ENABLED, "ryd_enabled");
|
|
||||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_DISLIKE_PERCENTAGE, "ryd_dislike_percentage");
|
|
||||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_COMPACT_LAYOUT, "ryd_compact_layout");
|
|
||||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_ESTIMATED_LIKE, "ryd_estimated_like");
|
|
||||||
Setting.migrateFromOldPreferences(revancedPrefs, RYD_TOAST_ON_CONNECTION_ERROR, "ryd_toast_on_connection_error");
|
|
||||||
|
|
||||||
// Migrate old saved data. Must be done here before the settings can be used by any other code.
|
// Migrate old saved data. Must be done here before the settings can be used by any other code.
|
||||||
applyOldSbOpacityToColor(SB_CATEGORY_SPONSOR_COLOR, DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY);
|
applyOldSbOpacityToColor(SB_CATEGORY_SPONSOR_COLOR, DEPRECATED_SB_CATEGORY_SPONSOR_OPACITY);
|
||||||
|
|||||||
@@ -83,12 +83,13 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
|
|||||||
String summary = str("revanced_spoof_video_streams_about_no_audio_tracks");
|
String summary = str("revanced_spoof_video_streams_about_no_audio_tracks");
|
||||||
|
|
||||||
switch (clientType) {
|
switch (clientType) {
|
||||||
case ANDROID_VR_1_61_48 ->
|
|
||||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
|
|
||||||
case ANDROID_CREATOR ->
|
case ANDROID_CREATOR ->
|
||||||
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
|
||||||
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
|
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
|
||||||
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
|
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
|
||||||
|
// VR 1.61 is not exposed in the UI and should never be reached here.
|
||||||
|
case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 ->
|
||||||
|
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
|
||||||
case IPADOS ->
|
case IPADOS ->
|
||||||
summary = str("revanced_spoof_video_streams_about_playback_failure")
|
summary = str("revanced_spoof_video_streams_about_playback_failure")
|
||||||
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
|
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import android.app.Dialog;
|
|||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.widget.Toolbar;
|
import android.widget.Toolbar;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.GmsCoreSupport;
|
||||||
import app.revanced.extension.shared.Logger;
|
import app.revanced.extension.shared.Logger;
|
||||||
import app.revanced.extension.shared.Utils;
|
import app.revanced.extension.shared.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
import app.revanced.extension.shared.settings.preference.ToolbarPreferenceFragment;
|
||||||
import app.revanced.extension.youtube.settings.YouTubeActivityHook;
|
import app.revanced.extension.youtube.settings.YouTubeActivityHook;
|
||||||
|
|
||||||
@@ -30,6 +32,17 @@ public class YouTubePreferenceFragment extends ToolbarPreferenceFragment {
|
|||||||
preferenceScreen = getPreferenceScreen();
|
preferenceScreen = getPreferenceScreen();
|
||||||
Utils.sortPreferenceGroups(preferenceScreen);
|
Utils.sortPreferenceGroups(preferenceScreen);
|
||||||
setPreferenceScreenToolbar(preferenceScreen);
|
setPreferenceScreenToolbar(preferenceScreen);
|
||||||
|
|
||||||
|
// Clunky work around until preferences are custom classes that manage themselves.
|
||||||
|
// Custom branding only works with non-root install. But the preferences must be
|
||||||
|
// added during patched because of difficulties detecting during patching if it's
|
||||||
|
// a root install. So instead the non-functional preferences are removed during
|
||||||
|
// runtime if the app is mount (root) installation.
|
||||||
|
if (GmsCoreSupport.isPackageNameOriginal()) {
|
||||||
|
removePreferences(
|
||||||
|
BaseSettings.CUSTOM_BRANDING_ICON.key,
|
||||||
|
BaseSettings.CUSTOM_BRANDING_NAME.key);
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "initialize failure", ex);
|
Logger.printException(() -> "initialize failure", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
android.useAndroidX = true
|
android.useAndroidX = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 5.42.0-dev.2
|
version = 5.45.0-dev.4
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ annotation = "1.9.1"
|
|||||||
appcompat = "1.7.0"
|
appcompat = "1.7.0"
|
||||||
okhttp = "5.0.0-alpha.14"
|
okhttp = "5.0.0-alpha.14"
|
||||||
retrofit = "2.11.0"
|
retrofit = "2.11.0"
|
||||||
guava = "33.4.0-jre"
|
guava = "33.5.0-jre"
|
||||||
protobuf-javalite = "4.32.0"
|
protobuf-javalite = "4.32.0"
|
||||||
protoc = "4.32.0"
|
protoc = "4.32.0"
|
||||||
protobuf = "0.9.5"
|
protobuf = "0.9.5"
|
||||||
|
|||||||
42
package-lock.json
generated
42
package-lock.json
generated
@@ -9,7 +9,7 @@
|
|||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.10.1",
|
"gradle-semantic-release-plugin": "^1.10.1",
|
||||||
"semantic-release": "^24.2.7"
|
"semantic-release": "^24.2.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@@ -6889,9 +6889,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/semantic-release": {
|
"node_modules/semantic-release": {
|
||||||
"version": "24.2.7",
|
"version": "24.2.9",
|
||||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.9.tgz",
|
||||||
"integrity": "sha512-g7RssbTAbir1k/S7uSwSVZFfFXwpomUB9Oas0+xi9KStSCmeDXcA7rNhiskjLqvUe/Evhx8fVCT16OSa34eM5g==",
|
"integrity": "sha512-phCkJ6pjDi9ANdhuF5ElS10GGdAKY6R1Pvt9lT3SFhOwM4T7QZE7MLpBDbNruUx/Q3gFD92/UOFringGipRqZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -6909,7 +6909,7 @@
|
|||||||
"find-versions": "^6.0.0",
|
"find-versions": "^6.0.0",
|
||||||
"get-stream": "^6.0.0",
|
"get-stream": "^6.0.0",
|
||||||
"git-log-parser": "^1.2.0",
|
"git-log-parser": "^1.2.0",
|
||||||
"hook-std": "^3.0.0",
|
"hook-std": "^4.0.0",
|
||||||
"hosted-git-info": "^8.0.0",
|
"hosted-git-info": "^8.0.0",
|
||||||
"import-from-esm": "^2.0.0",
|
"import-from-esm": "^2.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
@@ -6921,7 +6921,7 @@
|
|||||||
"read-package-up": "^11.0.0",
|
"read-package-up": "^11.0.0",
|
||||||
"resolve-from": "^5.0.0",
|
"resolve-from": "^5.0.0",
|
||||||
"semver": "^7.3.2",
|
"semver": "^7.3.2",
|
||||||
"semver-diff": "^4.0.0",
|
"semver-diff": "^5.0.0",
|
||||||
"signale": "^1.2.1",
|
"signale": "^1.2.1",
|
||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
},
|
},
|
||||||
@@ -7045,6 +7045,19 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/semantic-release/node_modules/hook-std": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-IHI4bEVOt3vRUDJ+bFA9VUJlo7SzvFARPNLw75pqSmAOP2HmTWfFJtPvLBrDrlgjEYXY9zs7SFdHPQaJShkSCQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semantic-release/node_modules/human-signals": {
|
"node_modules/semantic-release/node_modules/human-signals": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz",
|
||||||
@@ -7138,6 +7151,23 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/semantic-release/node_modules/semver-diff": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-0HbGtOm+S7T6NGQ/pxJSJipJvc4DK3FcRVMRkhsIwJDJ4Jcz5DQC1cPPzB5GhzyHjwttW878HaWQq46CkL3cqg==",
|
||||||
|
"deprecated": "Deprecated as the semver package now supports this built-in.",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^7.3.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semantic-release/node_modules/signal-exit": {
|
"node_modules/semantic-release/node_modules/signal-exit": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.10.1",
|
"gradle-semantic-release-plugin": "^1.10.1",
|
||||||
"semantic-release": "^24.2.7"
|
"semantic-release": "^24.2.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ public final class app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWi
|
|||||||
public static final fun getSpoofWifiPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSpoofWifiPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/all/misc/customcertificates/CustomCertificatesPatchKt {
|
||||||
|
public static final fun getCustomNetworkSecurityPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatchKt {
|
public final class app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatchKt {
|
||||||
public static final fun getEnableAndroidDebuggingPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
public static final fun getEnableAndroidDebuggingPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
}
|
}
|
||||||
@@ -184,6 +188,10 @@ public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatchKt {
|
|||||||
public static final fun getEnableDebugMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getEnableDebugMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/duolingo/energy/SkipEnergyRechargeAdsPatchKt {
|
||||||
|
public static final fun getSkipEnergyRechargeAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatchKt {
|
public final class app/revanced/patches/facebook/ads/mainfeed/HideSponsoredStoriesPatchKt {
|
||||||
public static final fun getHideSponsoredStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideSponsoredStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -269,7 +277,7 @@ public final class app/revanced/patches/instagram/feed/LimitFeedToFollowedProfil
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt {
|
public final class app/revanced/patches/instagram/hide/explore/HideExploreFeedKt {
|
||||||
public static final fun getHideExportFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideExploreFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt {
|
public final class app/revanced/patches/instagram/hide/navigation/HideNavigationButtonsKt {
|
||||||
@@ -280,10 +288,30 @@ public final class app/revanced/patches/instagram/hide/stories/HideStoriesKt {
|
|||||||
public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideStoriesPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/instagram/hide/suggestions/HideSuggestedContentKt {
|
||||||
|
public static final fun getHideSuggestedContent ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/instagram/misc/devmenu/EnableDeveloperMenuPatchKt {
|
||||||
|
public static final fun getEnableDeveloperMenuPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/instagram/misc/extension/SharedExtensionPatchKt {
|
public final class app/revanced/patches/instagram/misc/extension/SharedExtensionPatchKt {
|
||||||
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/instagram/misc/links/OpenLinksExternallyPatchKt {
|
||||||
|
public static final fun getOpenLinksExternallyPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/instagram/misc/share/domain/ChangeLinkSharingDomainPatchKt {
|
||||||
|
public static final fun getChangeLinkSharingDomainPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/instagram/misc/share/privacy/SanitizeSharingLinksPatchKt {
|
||||||
|
public static final fun getSanitizeSharingLinksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
|
public final class app/revanced/patches/instagram/misc/signature/SignatureCheckPatchKt {
|
||||||
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSignatureCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -372,6 +400,10 @@ public final class app/revanced/patches/music/interaction/permanentshuffle/Perma
|
|||||||
public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/layout/branding/CustomBrandingPatchKt {
|
||||||
|
public static final fun getCustomBrandingPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt {
|
public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt {
|
||||||
public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -451,9 +483,16 @@ public final class app/revanced/patches/music/misc/spoof/UserAgentClientSpoofPat
|
|||||||
public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatchKt {
|
||||||
|
public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
|
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
|
||||||
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
|
public static final fun is_7_16_or_greater ()Z
|
||||||
public static final fun is_7_33_or_greater ()Z
|
public static final fun is_7_33_or_greater ()Z
|
||||||
|
public static final fun is_8_05_or_greater ()Z
|
||||||
|
public static final fun is_8_10_or_greater ()Z
|
||||||
public static final fun is_8_11_or_greater ()Z
|
public static final fun is_8_11_or_greater ()Z
|
||||||
public static final fun is_8_15_or_greater ()Z
|
public static final fun is_8_15_or_greater ()Z
|
||||||
}
|
}
|
||||||
@@ -733,6 +772,14 @@ public final class app/revanced/patches/reddit/misc/tracking/url/SanitizeUrlQuer
|
|||||||
public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSanitizeUrlQueryPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/samsung/radio/misc/fix/crash/FixCrashPatchKt {
|
||||||
|
public static final fun getFixCrashPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/samsung/radio/restrictions/device/BypassDeviceChecksPatchKt {
|
||||||
|
public static final fun getBypassDeviceChecksPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt {
|
public final class app/revanced/patches/serviceportalbund/detection/root/RootDetectionPatchKt {
|
||||||
public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getRootDetectionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -997,11 +1044,6 @@ public final class app/revanced/patches/shared/misc/settings/preference/TextPref
|
|||||||
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
|
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatchKt {
|
|
||||||
public static final fun spoofVideoStreamsPatch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch;
|
|
||||||
public static synthetic fun spoofVideoStreamsPatch$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatchKt {
|
public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatchKt {
|
||||||
public static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -1146,6 +1188,10 @@ public final class app/revanced/patches/tiktok/misc/settings/SettingsPatchKt {
|
|||||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatchKt {
|
||||||
|
public static final fun getSanitizeShareUrlsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt {
|
public final class app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatchKt {
|
||||||
public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSpoofSimPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@@ -1411,8 +1457,8 @@ public final class app/revanced/patches/youtube/layout/formfactor/ChangeFormFact
|
|||||||
public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatchKt {
|
public final class app/revanced/patches/youtube/layout/hide/endscreencards/HideEndScreenCardsPatchKt {
|
||||||
public static final fun getHideEndscreenCardsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getHideEndScreenCardsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatchKt {
|
public final class app/revanced/patches/youtube/layout/hide/endscreensuggestion/HideEndScreenSuggestedVideoPatchKt {
|
||||||
@@ -1899,6 +1945,7 @@ public final class app/revanced/util/ResourceUtilsKt {
|
|||||||
public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V
|
public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V
|
||||||
public static final fun insertFirst (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)V
|
public static final fun insertFirst (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)V
|
||||||
public static final fun iterateXmlNodeChildren (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
|
public static final fun iterateXmlNodeChildren (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
|
||||||
|
public static final fun removeFromParent (Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/util/resource/ArrayResource : app/revanced/util/resource/BaseResource {
|
public final class app/revanced/util/resource/ArrayResource : app/revanced/util/resource/BaseResource {
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package app.revanced.patches.all.misc.customcertificates
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.PatchException
|
||||||
|
import app.revanced.patcher.patch.booleanOption
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patcher.patch.stringsOption
|
||||||
|
import app.revanced.util.Utils.trimIndentMultiline
|
||||||
|
import app.revanced.util.getNode
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
val customNetworkSecurityPatch = resourcePatch(
|
||||||
|
name = "Custom network security",
|
||||||
|
description = "Allows trusting custom certificate authorities for a specific domain.",
|
||||||
|
use = false
|
||||||
|
) {
|
||||||
|
|
||||||
|
val targetDomains by stringsOption(
|
||||||
|
key = "targetDomains",
|
||||||
|
title = "Target domains",
|
||||||
|
description = "List of domains to which the custom trust configuration will be applied (one domain per entry).",
|
||||||
|
default = listOf("example.com"),
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val includeSubdomains by booleanOption(
|
||||||
|
key = "includeSubdomains",
|
||||||
|
title = "Include subdomains",
|
||||||
|
description = "Applies the configuration to all subdomains of the target domains.",
|
||||||
|
default = false,
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val customCAFilePaths by stringsOption(
|
||||||
|
key = "customCAFilePaths",
|
||||||
|
title = "Custom CA file paths",
|
||||||
|
description = """
|
||||||
|
List of paths to files in PEM or DER format (one file path per entry).
|
||||||
|
|
||||||
|
Makes an app trust the provided custom certificate authorities (CAs),
|
||||||
|
for the specified domains, and if the option "Include Subdomains" is enabled then also the subdomains.
|
||||||
|
|
||||||
|
|
||||||
|
CA files will be bundled in res/raw/ of resulting APK
|
||||||
|
""".trimIndentMultiline(),
|
||||||
|
default = null,
|
||||||
|
required = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val allowUserCerts by booleanOption(
|
||||||
|
key = "allowUserCerts",
|
||||||
|
title = "Trust user added CAs",
|
||||||
|
description = "Makes an app trust certificates from the Android user store for the specified domains, and if the option \"Include Subdomains\" is enabled then also the subdomains.",
|
||||||
|
|
||||||
|
default = false,
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val allowSystemCerts by booleanOption(
|
||||||
|
key = "allowSystemCerts",
|
||||||
|
title = "Trust system CAs",
|
||||||
|
description = "Makes an app trust certificates from the Android system store for the specified domains, and and if the option \"Include Subdomains\" is enabled then also the subdomains.",
|
||||||
|
|
||||||
|
default = true,
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val allowCleartextTraffic by booleanOption(
|
||||||
|
key = "allowCleartextTraffic",
|
||||||
|
title = "Allow cleartext traffic (HTTP)",
|
||||||
|
description = "Allows unencrypted HTTP traffic for the specified domains, and if \"Include Subdomains\" is enabled then also the subdomains.",
|
||||||
|
|
||||||
|
default = false,
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val overridePins by booleanOption(
|
||||||
|
key = "overridePins",
|
||||||
|
title = "Override certificate pinning",
|
||||||
|
description = "Overrides certificate pinning for the specified domains and their subdomains if the option \"Include Subdomains\" is enabled to allow inspecting app traffic via a proxy.",
|
||||||
|
|
||||||
|
default = false,
|
||||||
|
required = true
|
||||||
|
)
|
||||||
|
|
||||||
|
fun generateNetworkSecurityConfig(): String {
|
||||||
|
val targetDomains = targetDomains ?: emptyList()
|
||||||
|
val includeSubdomains = includeSubdomains ?: false
|
||||||
|
val customCAFilePaths = customCAFilePaths ?: emptyList()
|
||||||
|
val allowUserCerts = allowUserCerts ?: false
|
||||||
|
val allowSystemCerts = allowSystemCerts ?: true
|
||||||
|
val allowCleartextTraffic = allowCleartextTraffic ?: false
|
||||||
|
val overridePins = overridePins ?: false
|
||||||
|
|
||||||
|
val domainsXML = buildString {
|
||||||
|
targetDomains.forEach {
|
||||||
|
appendLine(""" <domain includeSubdomains="$includeSubdomains">$it</domain>""")
|
||||||
|
}
|
||||||
|
}.trimEnd()
|
||||||
|
|
||||||
|
val trustAnchorsXML = buildString {
|
||||||
|
if (allowSystemCerts) {
|
||||||
|
appendLine(""" <certificates src="system" overridePins="$overridePins" />""")
|
||||||
|
}
|
||||||
|
if (allowUserCerts) {
|
||||||
|
appendLine(""" <certificates src="user" overridePins="$overridePins" />""")
|
||||||
|
}
|
||||||
|
customCAFilePaths.forEach { path ->
|
||||||
|
val fileName = path.substringAfterLast('/').substringBeforeLast('.')
|
||||||
|
appendLine(""" <certificates src="@raw/$fileName" overridePins="$overridePins" />""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trustAnchorsXML.isBlank()) {
|
||||||
|
throw PatchException("At least one trust anchor (System, User, or Custom CA) must be enabled.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return """
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<domain-config cleartextTrafficPermitted="$allowCleartextTraffic">
|
||||||
|
$domainsXML
|
||||||
|
<trust-anchors>
|
||||||
|
${trustAnchorsXML.trimEnd()}
|
||||||
|
</trust-anchors>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
execute {
|
||||||
|
val nscFileNameBare = "network_security_config"
|
||||||
|
val resXmlDir = "res/xml"
|
||||||
|
val resRawDir = "res/raw"
|
||||||
|
val nscFileNameWithSuffix = "$nscFileNameBare.xml"
|
||||||
|
|
||||||
|
|
||||||
|
document("AndroidManifest.xml").use { document ->
|
||||||
|
val applicationNode = document.getNode("application") as Element
|
||||||
|
applicationNode.setAttribute("android:networkSecurityConfig", "@xml/$nscFileNameBare")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File(get(resXmlDir), nscFileNameWithSuffix).apply {
|
||||||
|
writeText(generateNetworkSecurityConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (customCAFilePath in customCAFilePaths ?: emptyList()) {
|
||||||
|
val file = File(customCAFilePath)
|
||||||
|
if (!file.exists()) {
|
||||||
|
throw PatchException(
|
||||||
|
"The custom CA file path cannot be found: " +
|
||||||
|
file.absolutePath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.isFile) {
|
||||||
|
throw PatchException(
|
||||||
|
"The custom CA file path must be a file: "
|
||||||
|
+ file.absolutePath
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val caFileNameWithoutSuffix = customCAFilePath.substringAfterLast('/').substringBefore('.')
|
||||||
|
val caFile = File(customCAFilePath)
|
||||||
|
File(
|
||||||
|
get(resRawDir),
|
||||||
|
caFileNameWithoutSuffix
|
||||||
|
).writeText(
|
||||||
|
caFile.readText()
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,35 @@
|
|||||||
package app.revanced.patches.duolingo.debug
|
package app.revanced.patches.duolingo.debug
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import app.revanced.util.returnEarly
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val enableDebugMenuPatch = bytecodePatch(
|
val enableDebugMenuPatch = bytecodePatch(
|
||||||
name = "Enable debug menu",
|
name = "Enable debug menu",
|
||||||
use = false,
|
use = false
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.duolingo"("5.158.4"))
|
compatibleWith("com.duolingo")
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
initializeBuildConfigProviderFingerprint.method.apply {
|
// It seems all categories are allowed on release. Force this on anyway.
|
||||||
val insertIndex = initializeBuildConfigProviderFingerprint.patternMatch!!.startIndex
|
debugCategoryAllowOnReleaseBuildsFingerprint.method.returnEarly(true)
|
||||||
val register = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
// Change build config debug build flag.
|
||||||
insertIndex,
|
buildConfigProviderConstructorFingerprint.match(
|
||||||
"const/4 v$register, 0x1",
|
buildConfigProviderToStringFingerprint.classDef
|
||||||
)
|
).let {
|
||||||
|
val index = it.patternMatch!!.startIndex
|
||||||
|
|
||||||
|
it.method.apply {
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
addInstruction(
|
||||||
|
index + 1,
|
||||||
|
"const/4 v$register, 0x1"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,25 @@ import app.revanced.patcher.fingerprint
|
|||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
/**
|
internal val debugCategoryAllowOnReleaseBuildsFingerprint = fingerprint {
|
||||||
* The `BuildConfigProvider` class has two booleans:
|
returns("Z")
|
||||||
*
|
parameters()
|
||||||
* - `isChina`: (usually) compares "play" with "china"...except for builds in China
|
custom { method, classDef ->
|
||||||
* - `isDebug`: compares "release" with "debug" <-- we want to force this to `true`
|
method.name == "getAllowOnReleaseBuilds" && classDef.type == "Lcom/duolingo/debug/DebugCategory;"
|
||||||
*/
|
}
|
||||||
|
}
|
||||||
internal val initializeBuildConfigProviderFingerprint = fingerprint {
|
|
||||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
internal val buildConfigProviderConstructorFingerprint = fingerprint {
|
||||||
returns("V")
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||||
opcodes(Opcode.IPUT_BOOLEAN)
|
parameters()
|
||||||
strings("debug", "release", "china")
|
opcodes(Opcode.CONST_4)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val buildConfigProviderToStringFingerprint = fingerprint {
|
||||||
|
parameters()
|
||||||
|
returns("Ljava/lang/String;")
|
||||||
|
strings("BuildConfigProvider(") // Partial string match.
|
||||||
|
custom { method, _ ->
|
||||||
|
method.name == "toString"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patches.duolingo.energy
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the class found in [energyConfigToStringFingerprint].
|
||||||
|
*/
|
||||||
|
internal val initializeEnergyConfigFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||||
|
opcodes(Opcode.RETURN_VOID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class name currently is not obfuscated but it may be in the future.
|
||||||
|
internal val energyConfigToStringFingerprint = fingerprint {
|
||||||
|
parameters()
|
||||||
|
returns("Ljava/lang/String;")
|
||||||
|
strings("EnergyConfig(", "maxEnergy=") // Partial string matches.
|
||||||
|
custom { method, _ -> method.name == "toString" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package app.revanced.patches.duolingo.energy
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.util.findFieldFromToString
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val skipEnergyRechargeAdsPatch = bytecodePatch(
|
||||||
|
name = "Skip energy recharge ads",
|
||||||
|
description = "Skips watching ads to recharge energy."
|
||||||
|
) {
|
||||||
|
compatibleWith("com.duolingo")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
initializeEnergyConfigFingerprint
|
||||||
|
.match(energyConfigToStringFingerprint.classDef)
|
||||||
|
.method.apply {
|
||||||
|
val energyField = energyConfigToStringFingerprint.method
|
||||||
|
.findFieldFromToString("energy=")
|
||||||
|
val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
insertIndex,
|
||||||
|
"""
|
||||||
|
const/16 v0, 99
|
||||||
|
iput v0, p0, $energyField
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,11 +2,13 @@ package app.revanced.patches.finanzonline.detection.root
|
|||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
|
||||||
|
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val rootDetectionPatch = bytecodePatch(
|
val rootDetectionPatch = bytecodePatch(
|
||||||
name = "Remove root detection",
|
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
|
||||||
description = "Removes the check for root permissions.",
|
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION,
|
||||||
) {
|
) {
|
||||||
compatibleWith("at.gv.bmf.bmf2go")
|
compatibleWith("at.gv.bmf.bmf2go")
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ val spoofFeaturesPatch = bytecodePatch(
|
|||||||
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
|
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
|
||||||
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
|
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
|
||||||
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
|
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
|
||||||
|
"com.google.android.feature.PIXEL_2025_EXPERIENCE",
|
||||||
),
|
),
|
||||||
title = "Features to disable",
|
title = "Features to disable",
|
||||||
description = "Google Pixel exclusive features to disable." +
|
description = "Google Pixel exclusive features to disable." +
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package app.revanced.patches.idaustria.detection.root
|
package app.revanced.patches.idaustria.detection.root
|
||||||
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
|
||||||
|
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
|
||||||
import app.revanced.util.returnEarly
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val rootDetectionPatch = bytecodePatch(
|
val rootDetectionPatch = bytecodePatch(
|
||||||
name = "Remove root detection",
|
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
|
||||||
description = "Removes the check for root permissions and unlocked bootloader.",
|
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
|
||||||
) {
|
) {
|
||||||
compatibleWith("at.gv.oe.app")
|
compatibleWith("at.gv.oe.app")
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package app.revanced.patches.instagram.hide.explore
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal const val EXPLORE_KEY_TO_BE_HIDDEN = "sectional_items"
|
||||||
|
|
||||||
internal val exploreResponseJsonParserFingerprint = fingerprint {
|
internal val exploreResponseJsonParserFingerprint = fingerprint {
|
||||||
strings("sectional_items", "ExploreTopicalFeedResponse")
|
strings(EXPLORE_KEY_TO_BE_HIDDEN, "ExploreTopicalFeedResponse")
|
||||||
custom { method, _ -> method.name == "parseFromJson" }
|
custom { method, _ -> method.name == "parseFromJson" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,39 @@
|
|||||||
package app.revanced.patches.instagram.hide.explore
|
package app.revanced.patches.instagram.hide.explore
|
||||||
|
|
||||||
|
import app.revanced.patcher.Fingerprint
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
context(BytecodePatchContext)
|
||||||
|
internal fun Fingerprint.replaceJsonFieldWithBogus(
|
||||||
|
key: String,
|
||||||
|
) {
|
||||||
|
val targetStringIndex = stringMatches!!.first { match -> match.string == key }.index
|
||||||
|
val targetStringRegister = method.getInstruction<OneRegisterInstruction>(targetStringIndex).registerA
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacing the JSON key we want to skip with a random string that is not a valid JSON key.
|
||||||
|
* This way the feeds array will never be populated.
|
||||||
|
* Received JSON keys that are not handled are simply ignored, so there are no side effects.
|
||||||
|
*/
|
||||||
|
method.replaceInstruction(
|
||||||
|
targetStringIndex,
|
||||||
|
"const-string v$targetStringRegister, \"BOGUS\"",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val hideExportFeedPatch = bytecodePatch(
|
val hideExploreFeedPatch = bytecodePatch(
|
||||||
name = "Hide explore feed",
|
name = "Hide explore feed",
|
||||||
description = "Hides posts and reels from the explore/search page.",
|
description = "Hides posts and reels from the explore/search page.",
|
||||||
use = false
|
use = false,
|
||||||
) {
|
) {
|
||||||
compatibleWith("com.instagram.android")
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
exploreResponseJsonParserFingerprint.method.apply {
|
exploreResponseJsonParserFingerprint.replaceJsonFieldWithBogus(EXPLORE_KEY_TO_BE_HIDDEN)
|
||||||
val sectionalItemStringIndex = exploreResponseJsonParserFingerprint.stringMatches!!.first().index
|
|
||||||
val sectionalItemStringRegister = getInstruction<OneRegisterInstruction>(sectionalItemStringIndex).registerA
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replacing the JSON key we want to skip with a random string that is not a valid JSON key.
|
|
||||||
* This way the feeds array will never be populated.
|
|
||||||
* Received JSON keys that are not handled are simply ignored, so there are no side effects.
|
|
||||||
*/
|
|
||||||
replaceInstruction(
|
|
||||||
sectionalItemStringIndex,
|
|
||||||
"const-string v$sectionalItemStringRegister, \"BOGUS\""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ package app.revanced.patches.instagram.hide.navigation
|
|||||||
|
|
||||||
import app.revanced.patcher.fingerprint
|
import app.revanced.patcher.fingerprint
|
||||||
import app.revanced.patcher.patch.BytecodePatchContext
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
internal val initializeNavigationButtonsListFingerprint = fingerprint {
|
internal val initializeNavigationButtonsListFingerprint = fingerprint {
|
||||||
strings("Nav3")
|
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||||
parameters("Lcom/instagram/common/session/UserSession;", "Z")
|
parameters("Lcom/instagram/common/session/UserSession;", "Z")
|
||||||
returns("Ljava/util/List;")
|
returns("Ljava/util/List;")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.patches.instagram.hide.suggestions
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal val FEED_ITEM_KEYS_TO_BE_HIDDEN = arrayOf(
|
||||||
|
"clips_netego",
|
||||||
|
"stories_netego",
|
||||||
|
"in_feed_survey",
|
||||||
|
"bloks_netego",
|
||||||
|
"suggested_igd_channels",
|
||||||
|
"suggested_top_accounts",
|
||||||
|
"suggested_users",
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val feedItemParseFromJsonFingerprint = fingerprint {
|
||||||
|
strings(*FEED_ITEM_KEYS_TO_BE_HIDDEN, "FeedItem")
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package app.revanced.patches.instagram.hide.suggestions
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.instagram.hide.explore.replaceJsonFieldWithBogus
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val hideSuggestedContent = bytecodePatch(
|
||||||
|
name = "Hide suggested content",
|
||||||
|
description = "Hides suggested stories, reels, threads and survey from feed (Suggested posts will still be shown).",
|
||||||
|
use = false,
|
||||||
|
) {
|
||||||
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
FEED_ITEM_KEYS_TO_BE_HIDDEN.forEach { key ->
|
||||||
|
feedItemParseFromJsonFingerprint.replaceJsonFieldWithBogus(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.devmenu
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.util.Utils.trimIndentMultiline
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
|
import app.revanced.util.returnEarly
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val enableDeveloperMenuPatch = bytecodePatch(
|
||||||
|
name = "Enable developer menu",
|
||||||
|
description = """
|
||||||
|
Enables the developer menu, which can be found at the bottom of settings menu with name 'Internal Settings'.
|
||||||
|
|
||||||
|
It is recommended to use this patch with an alpha/beta Instagram release. Patching a stable release works, but the developer menu shows the developer flags as numbers and does not show a human readable description.
|
||||||
|
""".trimIndentMultiline(),
|
||||||
|
use = false
|
||||||
|
) {
|
||||||
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
with(clearNotificationReceiverFingerprint.method) {
|
||||||
|
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) {
|
||||||
|
val reference = getReference<MethodReference>()
|
||||||
|
opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
|
||||||
|
reference?.parameterTypes?.size == 1 &&
|
||||||
|
reference.parameterTypes.first() == "Lcom/instagram/common/session/UserSession;" &&
|
||||||
|
reference.returnType == "Z"
|
||||||
|
}.let { index ->
|
||||||
|
navigate(this).to(index).stop().returnEarly(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
package app.revanced.patches.instagram.misc.devmenu
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal val clearNotificationReceiverFingerprint = fingerprint {
|
||||||
|
custom { method, classDef ->
|
||||||
|
method.name == "onReceive" &&
|
||||||
|
classDef.type == "Lcom/instagram/notifications/push/ClearNotificationReceiver;"
|
||||||
|
}
|
||||||
|
strings("NOTIFICATION_DISMISSED")
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.links
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal const val TARGET_STRING = "Tracking.ARG_CLICK_SOURCE"
|
||||||
|
|
||||||
|
internal val inAppBrowserFunctionFingerprint = fingerprint {
|
||||||
|
returns("Z")
|
||||||
|
strings("TrackingInfo.ARG_MODULE_NAME", TARGET_STRING)
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.links
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/instagram/misc/links/OpenLinksExternallyPatch;"
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val openLinksExternallyPatch = bytecodePatch(
|
||||||
|
name = "Open links externally",
|
||||||
|
description = "Changes links to always open in your external browser, instead of the in-app browser.",
|
||||||
|
use = false,
|
||||||
|
) {
|
||||||
|
|
||||||
|
dependsOn(sharedExtensionPatch)
|
||||||
|
|
||||||
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
|
execute {
|
||||||
|
inAppBrowserFunctionFingerprint.let {
|
||||||
|
val stringMatchIndex = it.stringMatches?.first { match -> match.string == TARGET_STRING }!!.index
|
||||||
|
|
||||||
|
it.method.apply {
|
||||||
|
val urlResultObjIndex = indexOfFirstInstructionOrThrow(
|
||||||
|
stringMatchIndex, Opcode.MOVE_OBJECT_FROM16
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register that contains the url after moving from a higher register.
|
||||||
|
val urlRegister = getInstruction<TwoRegisterInstruction>(urlResultObjIndex).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
urlResultObjIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->openExternally(Ljava/lang/String;)Z
|
||||||
|
move-result v$urlRegister
|
||||||
|
return v$urlRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.share
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
|
context(BytecodePatchContext)
|
||||||
|
internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int) -> Unit) {
|
||||||
|
val fingerprintsToPatch = arrayOf(
|
||||||
|
permalinkResponseJsonParserFingerprint,
|
||||||
|
storyUrlResponseJsonParserFingerprint,
|
||||||
|
profileUrlResponseJsonParserFingerprint,
|
||||||
|
liveUrlResponseJsonParserFingerprint
|
||||||
|
)
|
||||||
|
|
||||||
|
for (fingerprint in fingerprintsToPatch) {
|
||||||
|
fingerprint.method.apply {
|
||||||
|
val putSharingUrlIndex = indexOfFirstInstruction(
|
||||||
|
permalinkResponseJsonParserFingerprint.stringMatches!!.first().index,
|
||||||
|
Opcode.IPUT_OBJECT
|
||||||
|
)
|
||||||
|
|
||||||
|
val sharingUrlRegister = getInstruction<TwoRegisterInstruction>(putSharingUrlIndex).registerA
|
||||||
|
|
||||||
|
block(putSharingUrlIndex, sharingUrlRegister)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.share
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal val permalinkResponseJsonParserFingerprint = fingerprint {
|
||||||
|
strings("permalink", "PermalinkResponse")
|
||||||
|
custom { method, _ -> method.name == "parseFromJson" }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val storyUrlResponseJsonParserFingerprint = fingerprint {
|
||||||
|
strings("story_item_to_share_url", "StoryItemUrlResponse")
|
||||||
|
custom { method, _ -> method.name == "parseFromJson" }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val profileUrlResponseJsonParserFingerprint = fingerprint {
|
||||||
|
strings("profile_to_share_url", "ProfileUrlResponse")
|
||||||
|
custom { method, _ -> method.name == "parseFromJson" }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val liveUrlResponseJsonParserFingerprint = fingerprint {
|
||||||
|
strings("live_to_share_url", "LiveItemLinkUrlResponse")
|
||||||
|
custom { method, _ -> method.name == "parseFromJson" }
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.share.domain
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.patch.stringOption
|
||||||
|
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.instagram.misc.share.editShareLinksPatch
|
||||||
|
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
|
||||||
|
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
|
||||||
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val changeLinkSharingDomainPatch = bytecodePatch(
|
||||||
|
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
|
||||||
|
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN,
|
||||||
|
use = false
|
||||||
|
) {
|
||||||
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
|
dependsOn(sharedExtensionPatch)
|
||||||
|
|
||||||
|
val customDomainHost by stringOption(
|
||||||
|
key = "domainName",
|
||||||
|
default = "imginn.com",
|
||||||
|
title = "Domain name",
|
||||||
|
description = "The domain name to use when sharing links."
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
getCustomShareDomainFingerprint.method.returnEarly(customDomainHost!!)
|
||||||
|
|
||||||
|
editShareLinksPatch { index, register ->
|
||||||
|
addInstructions(
|
||||||
|
index,
|
||||||
|
"""
|
||||||
|
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setCustomShareDomain(Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.share.domain
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/instagram/misc/share/domain/ChangeLinkSharingDomainPatch;"
|
||||||
|
|
||||||
|
internal val getCustomShareDomainFingerprint = fingerprint {
|
||||||
|
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
|
||||||
|
returns("Ljava/lang/String;")
|
||||||
|
parameters()
|
||||||
|
custom { method, classDef ->
|
||||||
|
method.name == "getCustomShareDomain" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package app.revanced.patches.instagram.misc.share.privacy
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.instagram.misc.share.editShareLinksPatch
|
||||||
|
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
|
||||||
|
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/extension/instagram/misc/share/privacy/SanitizeSharingLinksPatch;"
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val sanitizeSharingLinksPatch = bytecodePatch(
|
||||||
|
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
|
||||||
|
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
|
||||||
|
) {
|
||||||
|
compatibleWith("com.instagram.android")
|
||||||
|
|
||||||
|
dependsOn(sharedExtensionPatch)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
editShareLinksPatch { index, register ->
|
||||||
|
addInstructions(
|
||||||
|
index,
|
||||||
|
"""
|
||||||
|
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeSharingLink(Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package app.revanced.patches.music.layout.branding
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
|
import app.revanced.patches.music.misc.gms.Constants.MUSIC_MAIN_ACTIVITY_NAME
|
||||||
|
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
|
||||||
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
|
import app.revanced.patches.shared.layout.branding.baseCustomBrandingPatch
|
||||||
|
import app.revanced.patches.shared.misc.mapping.get
|
||||||
|
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||||
|
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversed
|
||||||
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
private val disableSplashAnimationPatch = bytecodePatch {
|
||||||
|
|
||||||
|
dependsOn(resourceMappingPatch)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
// The existing YT animation usually only shows for a fraction of a second,
|
||||||
|
// and the existing animation does not match the new splash screen
|
||||||
|
// causing the original YT Music logo to momentarily flash on screen as the animation starts.
|
||||||
|
//
|
||||||
|
// Could replace the lottie animation file with our own custom animation (app_launch.json),
|
||||||
|
// but the animation is not always the same size as the launch screen and it's still
|
||||||
|
// barely shown. Instead turn off the animation entirely (app will also launch a little faster).
|
||||||
|
cairoSplashAnimationConfigFingerprint.method.apply {
|
||||||
|
val mainActivityLaunchAnimation = resourceMappings["layout", "main_activity_launch_animation"]
|
||||||
|
val literalIndex = indexOfFirstLiteralInstructionOrThrow(
|
||||||
|
mainActivityLaunchAnimation
|
||||||
|
)
|
||||||
|
val insertIndex = indexOfFirstInstructionReversed(literalIndex) {
|
||||||
|
this.opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.name == "setContentView"
|
||||||
|
} + 1
|
||||||
|
val jumpIndex = indexOfFirstInstructionOrThrow(insertIndex) {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.parameterTypes?.firstOrNull() == "Ljava/lang/Runnable;"
|
||||||
|
} + 1
|
||||||
|
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
insertIndex,
|
||||||
|
"goto :skip_animation",
|
||||||
|
ExternalLabel("skip_animation", getInstruction(jumpIndex))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val customBrandingPatch = baseCustomBrandingPatch(
|
||||||
|
addResourcePatchName = "music",
|
||||||
|
originalLauncherIconName = "ic_launcher_release",
|
||||||
|
originalAppName = "@string/app_launcher_name",
|
||||||
|
originalAppPackageName = MUSIC_PACKAGE_NAME,
|
||||||
|
isYouTubeMusic = true,
|
||||||
|
numberOfPresetAppNames = 5,
|
||||||
|
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
|
||||||
|
mainActivityName = MUSIC_MAIN_ACTIVITY_NAME,
|
||||||
|
activityAliasNameWithIntents = MUSIC_MAIN_ACTIVITY_NAME,
|
||||||
|
preferenceScreen = PreferenceScreen.GENERAL,
|
||||||
|
|
||||||
|
block = {
|
||||||
|
dependsOn(sharedExtensionPatch, disableSplashAnimationPatch)
|
||||||
|
|
||||||
|
compatibleWith(
|
||||||
|
"com.google.android.apps.youtube.music"(
|
||||||
|
"7.29.52",
|
||||||
|
"8.10.52"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package app.revanced.patches.music.layout.branding
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.patches.music.shared.YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
|
||||||
|
|
||||||
|
internal val cairoSplashAnimationConfigFingerprint = fingerprint {
|
||||||
|
returns("V")
|
||||||
|
parameters("Landroid/os/Bundle;")
|
||||||
|
custom { method, classDef ->
|
||||||
|
method.name == "onCreate" && method.definingClass == YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,16 @@
|
|||||||
package app.revanced.patches.music.layout.compactheader
|
package app.revanced.patches.music.layout.compactheader
|
||||||
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
|
||||||
import app.revanced.patcher.fingerprint
|
import app.revanced.patcher.fingerprint
|
||||||
|
import app.revanced.util.literal
|
||||||
|
|
||||||
internal val constructCategoryBarFingerprint = fingerprint {
|
internal val chipCloudFingerprint = fingerprint {
|
||||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
|
||||||
returns("V")
|
returns("V")
|
||||||
parameters("Landroid/content/Context;", "L", "L", "L")
|
|
||||||
opcodes(
|
opcodes(
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.CONST,
|
Opcode.CONST,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.CONST_4,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.INVOKE_STATIC,
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT
|
||||||
Opcode.CONST,
|
|
||||||
Opcode.INVOKE_VIRTUAL
|
|
||||||
)
|
)
|
||||||
|
literal { chipCloud }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package app.revanced.patches.music.layout.compactheader
|
package app.revanced.patches.music.layout.compactheader
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patches.all.misc.resources.addResources
|
import app.revanced.patches.all.misc.resources.addResources
|
||||||
@@ -8,10 +8,14 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
|
|||||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
import app.revanced.patches.music.misc.settings.PreferenceScreen
|
||||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||||
|
import app.revanced.patches.shared.misc.mapping.get
|
||||||
|
import app.revanced.patches.shared.misc.mapping.resourceMappings
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.util.findFreeRegister
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
internal var chipCloud = -1L
|
||||||
|
private set
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
|
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCategoryBarPatch;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@@ -33,28 +37,21 @@ val hideCategoryBar = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
chipCloud = resourceMappings["layout", "chip_cloud"]
|
||||||
|
|
||||||
addResources("music", "layout.compactheader.hideCategoryBar")
|
addResources("music", "layout.compactheader.hideCategoryBar")
|
||||||
|
|
||||||
PreferenceScreen.GENERAL.addPreferences(
|
PreferenceScreen.GENERAL.addPreferences(
|
||||||
SwitchPreference("revanced_music_hide_category_bar"),
|
SwitchPreference("revanced_music_hide_category_bar"),
|
||||||
)
|
)
|
||||||
|
|
||||||
constructCategoryBarFingerprint.method.apply {
|
chipCloudFingerprint.method.apply {
|
||||||
val insertIndex = constructCategoryBarFingerprint.patternMatch!!.startIndex
|
val targetIndex = chipCloudFingerprint.patternMatch!!.endIndex
|
||||||
val register = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||||
val freeRegister = findFreeRegister(insertIndex, register)
|
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstruction(
|
||||||
insertIndex,
|
targetIndex + 1,
|
||||||
"""
|
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar(Landroid/view/View;)V"
|
||||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->hideCategoryBar()Z
|
|
||||||
move-result v$freeRegister
|
|
||||||
if-eqz v$freeRegister, :show
|
|
||||||
const/16 v$freeRegister, 0x8
|
|
||||||
invoke-virtual { v$register, v$freeRegister }, Landroid/view/View;->setVisibility(I)V
|
|
||||||
:show
|
|
||||||
nop
|
|
||||||
"""
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package app.revanced.patches.music.misc.fileprovider
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
|
||||||
|
import app.revanced.patches.music.utils.fix.fileprovider.fileProviderResolverFingerprint
|
||||||
|
|
||||||
|
internal fun fileProviderPatch(
|
||||||
|
youtubePackageName: String,
|
||||||
|
musicPackageName: String
|
||||||
|
) = bytecodePatch(
|
||||||
|
description = "Fixes broken YouTube Music file provider that prevents sharing with specific apps such as Instagram."
|
||||||
|
) {
|
||||||
|
finalize {
|
||||||
|
// Must do modification last, so change package name value is correctly set.
|
||||||
|
val musicChangedPackageName = setOrGetFallbackPackageName(musicPackageName)
|
||||||
|
|
||||||
|
// For some reason, if the app gets "android.support.FILE_PROVIDER_PATHS",
|
||||||
|
// the package name of YouTube is used, not the package name of the YT Music.
|
||||||
|
//
|
||||||
|
// There is no issue in the stock YT Music, but this is an issue in the GmsCore Build.
|
||||||
|
// https://github.com/ReVanced/revanced-patches/issues/55
|
||||||
|
//
|
||||||
|
// To solve this issue, replace the package name of YouTube with YT Music's package name.
|
||||||
|
fileProviderResolverFingerprint.method.addInstructionsWithLabels(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
const-string v0, "com.google.android.youtube.fileprovider"
|
||||||
|
invoke-static { p1, v0 }, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
|
||||||
|
move-result v0
|
||||||
|
if-nez v0, :fix
|
||||||
|
const-string v0, "$youtubePackageName.fileprovider"
|
||||||
|
invoke-static { p1, v0 }, Ljava/util/Objects;->equals(Ljava/lang/Object;Ljava/lang/Object;)Z
|
||||||
|
move-result v0
|
||||||
|
if-nez v0, :fix
|
||||||
|
goto :ignore
|
||||||
|
:fix
|
||||||
|
const-string p1, "$musicChangedPackageName.fileprovider"
|
||||||
|
:ignore
|
||||||
|
nop
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package app.revanced.patches.music.utils.fix.fileprovider
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal val fileProviderResolverFingerprint = fingerprint {
|
||||||
|
returns("L")
|
||||||
|
strings(
|
||||||
|
"android.support.FILE_PROVIDER_PATHS",
|
||||||
|
"Name must not be empty"
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package app.revanced.patches.music.misc.gms
|
package app.revanced.patches.music.misc.gms
|
||||||
|
|
||||||
object Constants {
|
object Constants {
|
||||||
|
internal const val MUSIC_MAIN_ACTIVITY_NAME = "com.google.android.apps.youtube.music.activities.MusicActivity"
|
||||||
|
|
||||||
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
|
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
|
||||||
internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music"
|
internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music"
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user