Compare commits

...

55 Commits

Author SHA1 Message Date
semantic-release-bot
97c4682ccc chore(release): 4.3.0-dev.7 [skip ci]
# [4.3.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.6...v4.3.0-dev.7) (2024-02-26)

### Features

* **OpeningHours:** Add `Fix crash` patch ([#2697](https://github.com/ReVanced/revanced-patches/issues/2697)) ([6742cd9](6742cd9232))
2024-02-26 03:52:58 +00:00
Linus
6742cd9232 feat(OpeningHours): Add Fix crash patch (#2697)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-02-26 04:50:59 +01:00
oSumAtrIX
5b2cc10adb docs: Fix broken links 2024-02-26 04:37:44 +01:00
semantic-release-bot
dbad6252fb chore(release): 4.3.0-dev.6 [skip ci]
# [4.3.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.5...v4.3.0-dev.6) (2024-02-25)

### Features

* **VSCO - Unlock pro:** Constrain to last working version ([0f7ed84](0f7ed841d1))
2024-02-25 18:30:14 +00:00
oSumAtrIX
0f7ed841d1 feat(VSCO - Unlock pro): Constrain to last working version 2024-02-25 19:28:12 +01:00
semantic-release-bot
d33d7d8f35 chore(release): 4.3.0-dev.5 [skip ci]
# [4.3.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.4...v4.3.0-dev.5) (2024-02-25)

### Features

* Remove unnecessary description from patch ([348e42a](348e42a374))
* **Twitter - Unlock downloads:** Unlock GIF downloads ([3200da8](3200da8657))
2024-02-25 07:02:56 +00:00
oSumAtrIX
3200da8657 feat(Twitter - Unlock downloads): Unlock GIF downloads 2024-02-25 08:00:29 +01:00
oSumAtrIX
348e42a374 feat: Remove unnecessary description from patch 2024-02-25 06:51:51 +01:00
oSumAtrIX
cbbac445b6 chore: Rename issue templates 2024-02-25 03:37:53 +01:00
oSumAtrIX
1593d1352a ci: Fix indentation in workflow 2024-02-24 01:14:45 +01:00
oSumAtrIX
c6fedaa7bc docs: Break long lines 2024-02-23 04:12:28 +01:00
oSumAtrIX
d070aebec4 docs: Fix mistakes and wording 2024-02-23 04:12:28 +01:00
oSumAtrIX
d583256f06 docs: Remove documentation section
The documentation for patches is being moved to the ReVanced Patcher repository. The reason for this is because the documentation about how to create patches using ReVanced Patcher, belongs in the ReVanced Patcher repository, whereas documentation specific to the public API of ReVanced Patches belongs in this repository. Because the public API has no documentation yet, the section is removed until then.
2024-02-23 02:55:45 +01:00
oSumAtrIX
fc67d284f7 ci: Fix PR builds by adding missing GitHub token 2024-02-23 02:23:50 +01:00
semantic-release-bot
d3f3f81b75 chore(release): 4.3.0-dev.4 [skip ci]
# [4.3.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.3...v4.3.0-dev.4) (2024-02-22)

### Bug Fixes

* Compile DEX without debugging information ([afe7f06](afe7f0605e))
* Use deprecated members to ensure backwards compatibility ([a6d8e42](a6d8e4210f))

### Features

* **X:** Add `Open links as query` patch ([#2730](https://github.com/ReVanced/revanced-patches/issues/2730)) ([43359b9](43359b95eb))
2024-02-22 00:13:48 +00:00
oSumAtrIX
8e8600c7c3 chore: Update fingerprint
The compiler of ReVanced Integrations now compiles the target method without `AccessFlags.Public`.
2024-02-22 01:11:17 +01:00
oSumAtrIX
ea33863083 ci: Do not start a Gradle daemon for PR builds
Because there are no subsequent builds, a daemon is not necessary
2024-02-22 01:10:09 +01:00
oSumAtrIX
a6d8e4210f fix: Use deprecated members to ensure backwards compatibility
By migrating to early to new APIs of ReVanced Patcher, if you were to use old versions of ReVanced Patcher, you would get compatibility issues. By using deprecated members until most have updated ReVanced Patcher, we can ensure seamless migration.
2024-02-22 01:10:09 +01:00
oSumAtrIX
1e3356808d ci: Split release into a separate PR build workflow
Because the release workflow already runs on dev and main, it is not necessary to also trigger it for PRs.
2024-02-22 01:07:05 +01:00
dic1911
43359b95eb feat(X): Add Open links as query patch (#2730)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-02-22 01:07:05 +01:00
oSumAtrIX
afe7f0605e fix: Compile DEX without debugging information 2024-02-21 04:15:38 +01:00
oSumAtrIX
8916789f7a build: Publish to GitHub Packages 2024-02-21 04:15:38 +01:00
oSumAtrIX
0d14aa1191 build: Sign release artifacts 2024-02-21 04:15:38 +01:00
oSumAtrIX
376dda6e81 build: Bump dependencies
This commit also migrates away from deprecated to new APIs
2024-02-21 04:07:32 +01:00
semantic-release-bot
ff8b58b645 chore(release): 4.3.0-dev.3 [skip ci]
# [4.3.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.2...v4.3.0-dev.3) (2024-02-20)

### Features

* **YouTube - Change header:** Improve patch option description ([e775bc2](e775bc2cae))
* **YouTube - Custom branding:** Improve patch option description ([f4b888b](f4b888be56))
2024-02-20 21:43:11 +00:00
oSumAtrIX
f4b888be56 feat(YouTube - Custom branding): Improve patch option description 2024-02-20 22:41:06 +01:00
oSumAtrIX
e775bc2cae feat(YouTube - Change header): Improve patch option description 2024-02-20 22:41:06 +01:00
oSumAtrIX
5c566753a8 build: Bump dependencies 2024-02-14 02:44:25 +01:00
oSumAtrIX
968ebf9f50 build: Bump Gradle 2024-02-14 02:41:21 +01:00
oSumAtrIX
75c510d876 chore: Fix ReplaceWith of Deprecated annotation 2024-02-13 03:27:03 +01:00
oSumAtrIX
72528cb2f1 chore: Remove dummy subproject
It is not necessary anymore
2024-02-13 02:58:24 +01:00
oSumAtrIX
81d79111cf chore: Add .editorconfig 2024-02-13 02:55:07 +01:00
oSumAtrIX
33036092b4 build: Bump dependencies 2024-02-13 02:54:40 +01:00
semantic-release-bot
f5f88092b6 chore(release): 4.3.0-dev.2 [skip ci]
# [4.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.1...v4.3.0-dev.2) (2024-02-09)

### Features

* **Sync for Reddit:** Add `Fix /s/ links` patch ([0434d88](0434d8812b))
2024-02-09 02:47:31 +00:00
oSumAtrIX
0434d8812b feat(Sync for Reddit): Add Fix /s/ links patch 2024-02-09 03:45:37 +01:00
semantic-release-bot
ec38b8e51c chore(release): 4.3.0-dev.1 [skip ci]
# [4.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0-dev.1) (2024-02-09)

### Features

* **YouTube - Change start page:** Add more start pages ([96f9b73](96f9b73c74))
2024-02-09 00:17:34 +00:00
oSumAtrIX
96f9b73c74 feat(YouTube - Change start page): Add more start pages 2024-02-09 00:50:16 +01:00
semantic-release-bot
1502fe1f7f chore(release): 4.2.0 [skip ci]
# [4.2.0](https://github.com/ReVanced/revanced-patches/compare/v4.1.0...v4.2.0) (2024-02-08)

### Bug Fixes

* **Infinity for Reddit - Unlock subscription:** Do not crash by patching billing client ([53b29ea](53b29ea270))

### Features

* **X:** Add `Hide view count` patch ([1bf9582](1bf9582437))
* **X:** Add `Unlock downloads` patch ([3343b5c](3343b5cb12))
2024-02-08 19:17:40 +00:00
oSumAtrIX
824d094394 chore: Merge branch dev to main (#2693) 2024-02-08 20:15:32 +01:00
semantic-release-bot
010471a745 chore(release): 4.2.0-dev.1 [skip ci]
# [4.2.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.1.1-dev.1...v4.2.0-dev.1) (2024-02-08)

### Features

* **X:** Add `Hide view count` patch ([1bf9582](1bf9582437))
* **X:** Add `Unlock downloads` patch ([3343b5c](3343b5cb12))
2024-02-08 19:13:57 +00:00
oSumAtrIX
3343b5cb12 feat(X): Add Unlock downloads patch 2024-02-08 20:11:18 +01:00
oSumAtrIX
1bf9582437 feat(X): Add Hide view count patch 2024-02-08 20:08:44 +01:00
semantic-release-bot
ea09d4b520 chore(release): 4.1.1-dev.1 [skip ci]
## [4.1.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.1.0...v4.1.1-dev.1) (2024-02-07)

### Bug Fixes

* **Infinity for Reddit - Unlock subscription:** Do not crash by patching billing client ([53b29ea](53b29ea270))
2024-02-07 15:19:04 +00:00
oSumAtrIX
53b29ea270 fix(Infinity for Reddit - Unlock subscription): Do not crash by patching billing client 2024-02-07 16:16:33 +01:00
oSumAtrIX
fd11e2b969 chore: Fix typo in README 2024-02-05 23:24:05 +01:00
semantic-release-bot
65a32ee52e chore(release): 4.1.0 [skip ci]
# [4.1.0](https://github.com/ReVanced/revanced-patches/compare/v4.0.2...v4.1.0) (2024-02-05)

### Bug Fixes

* **Infinity for Reddit - Unlock subscription:** Restore functionality on v7.0.0 ([2c50c25](2c50c25a36))
* **YouTube:** Correctly show channel page on tablet devices ([#2656](https://github.com/ReVanced/revanced-patches/issues/2656)) ([047069c](047069ca8a))

### Features

* **YouTube - Custom filter:** Custom filtering of the protocol buffer ([#2682](https://github.com/ReVanced/revanced-patches/issues/2682)) ([19a9d11](19a9d113d9))
* **YouTube:** Support version `19.04.37` ([#2687](https://github.com/ReVanced/revanced-patches/issues/2687)) ([8b1cdd5](8b1cdd5c6a))
2024-02-05 19:26:27 +00:00
oSumAtrIX
7b2e32d88c chore: Merge branch dev to main (#2657) 2024-02-05 20:24:31 +01:00
semantic-release-bot
f18edb262d chore(release): 4.1.0-dev.2 [skip ci]
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2024-02-04)

### Features

* **YouTube:** Support version `19.04.37` ([#2687](https://github.com/ReVanced/revanced-patches/issues/2687)) ([8b1cdd5](8b1cdd5c6a))
2024-02-04 17:40:14 +00:00
LisoUseInAIKyrios
8b1cdd5c6a feat(YouTube): Support version 19.04.37 (#2687) 2024-02-04 21:38:19 +04:00
semantic-release-bot
3bd41fb67f chore(release): 4.1.0-dev.1 [skip ci]
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2024-02-02)

### Features

* **YouTube - Custom filter:** Custom filtering of the protocol buffer ([#2682](https://github.com/ReVanced/revanced-patches/issues/2682)) ([19a9d11](19a9d113d9))
2024-02-02 08:17:53 +00:00
LisoUseInAIKyrios
19a9d113d9 feat(YouTube - Custom filter): Custom filtering of the protocol buffer (#2682) 2024-02-02 12:15:34 +04:00
semantic-release-bot
61ee51b856 chore(release): 4.0.3-dev.2 [skip ci]
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2024-02-01)

### Bug Fixes

* **Infinity for Reddit - Unlock subscription:** Restore functionality on v7.0.0 ([2c50c25](2c50c25a36))
2024-02-01 23:12:20 +00:00
oSumAtrIX
2c50c25a36 fix(Infinity for Reddit - Unlock subscription): Restore functionality on v7.0.0 2024-02-02 00:10:00 +01:00
oSumAtrIX
f5e7bf6e98 docs: Fix feature request template mentioning bug report template 2024-01-31 11:10:07 +01:00
LisoUseInAIKyrios
bba35d5cb5 chore: fix patch typo in WideSearchbarPatch 2024-01-29 17:31:57 +04:00
134 changed files with 1737 additions and 769 deletions

3
.editorconfig Normal file
View File

@@ -0,0 +1,3 @@
[*.{kt,kts}]
ktlint_code_style = intellij_idea
ktlint_standard_no-wildcard-imports = disabled

View File

@@ -71,7 +71,7 @@ body:
Before creating a new feature request, please keep the following in mind:
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-patches/labels/Feature%20request).
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-patches/blob/main/CONTRIBUTING.md).
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-patches/blob/main/CONTRIBUTING.md).
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
- type: textarea
attributes:

View File

@@ -0,0 +1,25 @@
name: Build pull request
on:
workflow_dispatch:
pull_request:
branches:
- dev
jobs:
release:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build --no-daemon

View File

@@ -6,10 +6,6 @@ on:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
jobs:
release:
@@ -41,6 +37,13 @@ jobs:
- name: Install dependencies
run: npm install
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
fingerprint: ${{ env.GPG_FINGERPRINT }}
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}

View File

@@ -33,7 +33,7 @@
{
"assets": [
{
"path": "build/libs/*.jar"
"path": "build/libs/revanced-patches*"
},
{
"path": "patches.json"

View File

@@ -1,3 +1,123 @@
# [4.3.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.6...v4.3.0-dev.7) (2024-02-26)
### Features
* **OpeningHours:** Add `Fix crash` patch ([#2697](https://github.com/ReVanced/revanced-patches/issues/2697)) ([0d011b8](https://github.com/ReVanced/revanced-patches/commit/0d011b876ecf05031a7daa54ab7e6d3506728a47))
# [4.3.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.5...v4.3.0-dev.6) (2024-02-25)
### Features
* **VSCO - Unlock pro:** Constrain to last working version ([6dd4a7c](https://github.com/ReVanced/revanced-patches/commit/6dd4a7c29e48c3bc517bbdd7ed160624c36c2333))
# [4.3.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.4...v4.3.0-dev.5) (2024-02-25)
### Features
* Remove unnecessary description from patch ([1a89dd9](https://github.com/ReVanced/revanced-patches/commit/1a89dd9f8cd0c614055a9da97338839b77a25ed1))
* **Twitter - Unlock downloads:** Unlock GIF downloads ([d0f91c8](https://github.com/ReVanced/revanced-patches/commit/d0f91c8550592723e1252e1af2971b508591dd59))
# [4.3.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.3...v4.3.0-dev.4) (2024-02-22)
### Bug Fixes
* Compile DEX without debugging information ([f5df957](https://github.com/ReVanced/revanced-patches/commit/f5df9578669f71a67411bc93a25a7e8da43610d0))
* Use deprecated members to ensure backwards compatibility ([083bd40](https://github.com/ReVanced/revanced-patches/commit/083bd4009231b9612394b4496ca1d329947d6577))
### Features
* **X:** Add `Open links as query` patch ([#2730](https://github.com/ReVanced/revanced-patches/issues/2730)) ([ba75a51](https://github.com/ReVanced/revanced-patches/commit/ba75a51b71dbb9157db230b3e97a90361019fe30))
# [4.3.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.2...v4.3.0-dev.3) (2024-02-20)
### Features
* **YouTube - Change header:** Improve patch option description ([3b8bc08](https://github.com/ReVanced/revanced-patches/commit/3b8bc08d4ed3a3a0f96d2f476e5059840b9f9d9b))
* **YouTube - Custom branding:** Improve patch option description ([e27f56c](https://github.com/ReVanced/revanced-patches/commit/e27f56c8a34d41167b290f47280276c1c6003876))
# [4.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.1...v4.3.0-dev.2) (2024-02-09)
### Features
* **Sync for Reddit:** Add `Fix /s/ links` patch ([f15ef3f](https://github.com/ReVanced/revanced-patches/commit/f15ef3f63460254236185f8e22c9395db4db9465))
# [4.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0-dev.1) (2024-02-09)
### Features
* **YouTube - Change start page:** Add more start pages ([cc1d9b7](https://github.com/ReVanced/revanced-patches/commit/cc1d9b743633c619fb6acc428e884c1c9b53e10b))
# [4.2.0](https://github.com/ReVanced/revanced-patches/compare/v4.1.0...v4.2.0) (2024-02-08)
### Bug Fixes
* **Infinity for Reddit - Unlock subscription:** Do not crash by patching billing client ([7d76e2e](https://github.com/ReVanced/revanced-patches/commit/7d76e2e43c69b2b75f40a15a9147d041c77cbcd9))
### Features
* **X:** Add `Hide view count` patch ([bf064ec](https://github.com/ReVanced/revanced-patches/commit/bf064ecc1d5de8b592d14d34acfa1a4314c374ba))
* **X:** Add `Unlock downloads` patch ([2c20844](https://github.com/ReVanced/revanced-patches/commit/2c20844eaae698f185a9d321e2c70bde4b485cee))
# [4.2.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.1.1-dev.1...v4.2.0-dev.1) (2024-02-08)
### Features
* **X:** Add `Hide view count` patch ([bf064ec](https://github.com/ReVanced/revanced-patches/commit/bf064ecc1d5de8b592d14d34acfa1a4314c374ba))
* **X:** Add `Unlock downloads` patch ([2c20844](https://github.com/ReVanced/revanced-patches/commit/2c20844eaae698f185a9d321e2c70bde4b485cee))
## [4.1.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.1.0...v4.1.1-dev.1) (2024-02-07)
### Bug Fixes
* **Infinity for Reddit - Unlock subscription:** Do not crash by patching billing client ([7d76e2e](https://github.com/ReVanced/revanced-patches/commit/7d76e2e43c69b2b75f40a15a9147d041c77cbcd9))
# [4.1.0](https://github.com/ReVanced/revanced-patches/compare/v4.0.2...v4.1.0) (2024-02-05)
### Bug Fixes
* **Infinity for Reddit - Unlock subscription:** Restore functionality on v7.0.0 ([bf19af9](https://github.com/ReVanced/revanced-patches/commit/bf19af99cb522f9027a4b3ae42d6258ac71758e5))
* **YouTube:** Correctly show channel page on tablet devices ([#2656](https://github.com/ReVanced/revanced-patches/issues/2656)) ([c7c9700](https://github.com/ReVanced/revanced-patches/commit/c7c9700d93caeae105916d33376670f525276fac))
### Features
* **YouTube - Custom filter:** Custom filtering of the protocol buffer ([#2682](https://github.com/ReVanced/revanced-patches/issues/2682)) ([872a5b6](https://github.com/ReVanced/revanced-patches/commit/872a5b6d8969ab1569cd57ece3c400c3741049be))
* **YouTube:** Support version `19.04.37` ([#2687](https://github.com/ReVanced/revanced-patches/issues/2687)) ([c23e023](https://github.com/ReVanced/revanced-patches/commit/c23e0233cf5c28d354132443d227b42ddc4a3dad))
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2024-02-04)
### Features
* **YouTube:** Support version `19.04.37` ([#2687](https://github.com/ReVanced/revanced-patches/issues/2687)) ([c23e023](https://github.com/ReVanced/revanced-patches/commit/c23e0233cf5c28d354132443d227b42ddc4a3dad))
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2024-02-02)
### Features
* **YouTube - Custom filter:** Custom filtering of the protocol buffer ([#2682](https://github.com/ReVanced/revanced-patches/issues/2682)) ([872a5b6](https://github.com/ReVanced/revanced-patches/commit/872a5b6d8969ab1569cd57ece3c400c3741049be))
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2024-02-01)
### Bug Fixes
* **Infinity for Reddit - Unlock subscription:** Restore functionality on v7.0.0 ([bf19af9](https://github.com/ReVanced/revanced-patches/commit/bf19af99cb522f9027a4b3ae42d6258ac71758e5))
## [4.0.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.0.2...v4.0.3-dev.1) (2024-01-28)

View File

@@ -64,15 +64,15 @@ This document describes how to contribute to ReVanced Patches.
## 📖 Resources to help you get started
* The [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs) provides the fundamentals of patches
and everything necessary to create your own patch from scratch
* The [documentation](https://github.com/ReVanced/revanced-patcher/tree/docs/docs) contains the fundamentals
of ReVanced Patcher and how to use ReVanced Patcher to create patches
* [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
* [Issues](https://github.com/ReVanced/revanced-patches/issues) are where we keep track of bugs and feature requests
## 🙏 Submitting a feature request
Features can be requested by opening an issue using the
[Feature request issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Feature+request&projects=&template=feature-request.yml&title=feat%3A+).
[Feature request issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
> **Note**
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Patches.
@@ -81,7 +81,7 @@ Features can be requested by opening an issue using the
## 🐞 Submitting a bug report
If you encounter a bug while using ReVanced Patches, open an issue using the
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Bug+report&projects=&template=bug-report.yml&title=bug%3A+).
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
## 🧑‍⚖️ Guidelines for requesting or contributing patches
@@ -110,7 +110,7 @@ are unaffected by this change.
## 📝 How to contribute
1. Before contributing, it is recommended to open an issue to discuss your change
1. Before contributing, it is recommended to open an issue to discuss your change
with the maintainers of ReVanced Patches. This will help you determine whether your change is acceptable
and whether it is worth your time to implement it
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`

View File

@@ -67,7 +67,7 @@ This repository contains a collection of ReVanced Patches.
## ❓ About
Patches are small modifications to Android apps that allow you to change the behaviour of or add new features,
Patches are small modifications to Android apps that allow you to change the behavior of or add new features,
block ads, customize the appearance, and much more.
## 💪 Features
@@ -77,11 +77,11 @@ Some of the features the patches provide are:
* 🚫 **Block ads**: Say goodbye to ads
***Customize your app**: Personalize the appearance of apps with various layouts and themes
* 🪄 **Add new features**: Extend the functionality of apps with lots of new features
* ⚙️ **Miscellaneous and general purpose**: Rename packages, enable debugging, disable screen capture restrictions,
export activities, etc.
* ⚙️ **Miscellaneous and general purpose**: Rename packages, enable debugging, disable screen capture restrictions,
export activities, etc.
***And much more!**
For a full list of all available patches, visit [revanced.app/patches](https://revanced.app/patches).
For a complete list of all available patches, visit [revanced.app/patches](https://revanced.app/patches).
## 🚀 How to get started
@@ -93,17 +93,13 @@ You can use [ReVanced CLI](https://github.com/ReVanced/revanced-cli) or [ReVance
Thank you for considering contributing to ReVanced Patches. You can find the contribution guidelines [here](CONTRIBUTING.md).
### 📃 Documentation
The documentation provides the fundamentals of patches and everything necessary to create your own patch from scratch.
You can find it [here](https://github.com/ReVanced/revanced-patches/tree/docs/docs).
### 🛠️ Building
In order to build ReVanced Patches, you can follow the [ReVanced documentation](https://github.com/ReVanced/revanced-documentation).
To build ReVanced Patches, you can follow the [ReVanced documentation](https://github.com/ReVanced/revanced-documentation).
## 📜 Licence
ReVanced Patches is licensed under the GPLv3 licence. Please see the [licence file](LICENSE) for more information.
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced patches as long as you track changes/dates in source files.
Any modifications to ReVanced Patches must also be made available under the GPL along with build & install instructions.
ReVanced Patches is licensed under the GPLv3 license. Please see the [license file](LICENSE) for more information.
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced Patches as long as you track changes/dates in source files.
Any modifications to ReVanced Patches must also be made available under the GPL,
along with build & install instructions.

View File

@@ -1,3 +1,7 @@
public final class app/revanced/generator/MainKt {
public static synthetic fun main ([Ljava/lang/String;)V
}
public final class app/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
@@ -406,6 +410,12 @@ public final class app/revanced/patches/nyx/misc/pro/UnlockProPatch : app/revanc
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/openinghours/misc/fix/crash/FixCrashPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/openinghours/misc/fix/crash/FixCrashPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -550,6 +560,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/detec
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -1065,6 +1081,18 @@ public final class app/revanced/patches/twitch/misc/settings/SettingsResourcePat
public static final field INSTANCE Lapp/revanced/patches/twitch/misc/settings/SettingsResourcePatch;
}
public final class app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/twitter/layout/viewcount/HideViewCountPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/twitter/layout/viewcount/HideViewCountPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch : app/revanced/patcher/patch/ResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch;
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
@@ -1092,6 +1120,12 @@ public final class app/revanced/patches/twitter/misc/hook/patch/recommendation/H
public static final field INSTANCE Lapp/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch;
}
public final class app/revanced/patches/twitter/misc/links/OpenLinksWithAppChooserPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/twitter/misc/links/OpenLinksWithAppChooserPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/vsco/misc/pro/UnlockProPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/vsco/misc/pro/UnlockProPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@@ -1420,6 +1454,10 @@ public final class app/revanced/patches/youtube/layout/startupshortsreset/Disabl
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint {
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsFingerprint;
}
public final class app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V

View File

@@ -1,9 +1,10 @@
import org.gradle.kotlin.dsl.support.listFilesOrdered
plugins {
kotlin("jvm") version "1.9.22"
alias(libs.plugins.kotlin)
alias(libs.plugins.binary.compatibility.validator)
`maven-publish`
signing
}
group = "app.revanced"
@@ -12,7 +13,14 @@ repositories {
mavenCentral()
mavenLocal()
google()
maven { url = uri("https://jitpack.io") }
maven {
// A repository must be speficied for some reason. "registry" is a dummy.
url = uri("https://maven.pkg.github.com/revanced/registry")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
}
}
}
dependencies {
@@ -22,34 +30,32 @@ dependencies {
implementation(libs.guava)
// Used in JsonGenerator.
implementation(libs.gson)
// A dependency to the Android library unfortunately fails the build, which is why this is required.
compileOnly(project("dummy"))
}
kotlin {
jvmToolchain(11)
}
tasks.withType(Jar::class) {
exclude("app/revanced/meta")
manifest {
attributes["Name"] = "ReVanced Patches"
attributes["Description"] = "Patches for ReVanced."
attributes["Version"] = version
attributes["Timestamp"] = System.currentTimeMillis().toString()
attributes["Source"] = "git@github.com:revanced/revanced-patches.git"
attributes["Author"] = "ReVanced"
attributes["Contact"] = "contact@revanced.app"
attributes["Origin"] = "https://revanced.app"
attributes["License"] = "GNU General Public License v3.0"
}
}
tasks {
register<DefaultTask>("generateBundle") {
description = "Generate DEX files and add them in the JAR file"
withType(Jar::class) {
exclude("app/revanced/meta")
manifest {
attributes["Name"] = "ReVanced Patches"
attributes["Description"] = "Patches for ReVanced."
attributes["Version"] = version
attributes["Timestamp"] = System.currentTimeMillis().toString()
attributes["Source"] = "git@github.com:revanced/revanced-patches.git"
attributes["Author"] = "ReVanced"
attributes["Contact"] = "contact@revanced.app"
attributes["Origin"] = "https://revanced.app"
attributes["License"] = "GNU General Public License v3.0"
}
}
register("buildDexJar") {
description = "Build and add a DEX to the JAR file"
group = "build"
dependsOn(build)
@@ -57,39 +63,50 @@ tasks {
val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools")
.listFilesOrdered().last().resolve("d8").absolutePath
val artifacts = configurations.archives.get().allArtifacts.files.files.first().absolutePath
val patchesJar = configurations.archives.get().allArtifacts.files.files.first().absolutePath
val workingDirectory = layout.buildDirectory.dir("libs").get().asFile
exec {
workingDir = workingDirectory
commandLine = listOf(d8, artifacts)
commandLine = listOf(d8, "--release", patchesJar)
}
exec {
workingDir = workingDirectory
commandLine = listOf("zip", "-u", artifacts, "classes.dex")
commandLine = listOf("zip", "-u", patchesJar, "classes.dex")
}
}
}
register<JavaExec>("generateMeta") {
description = "Generate metadata for this bundle"
register<JavaExec>("generatePatchesFiles") {
description = "Generate patches files"
dependsOn(build)
classpath = sourceSets["main"].runtimeClasspath
mainClass.set("app.revanced.meta.IPatchesFileGenerator")
mainClass.set("app.revanced.generator.MainKt")
}
// Required to run tasks because Gradle semantic-release plugin runs the publish task.
// Needed by gradle-semantic-release-plugin.
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
named("publish") {
dependsOn("generateBundle")
dependsOn("generateMeta")
publish {
dependsOn("buildDexJar")
dependsOn("generatePatchesFiles")
}
}
publishing {
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/revanced/revanced-patches")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
publications {
create<MavenPublication>("revanced-patches-publication") {
from(components["java"])
@@ -120,4 +137,10 @@ publishing {
}
}
}
}
}
signing {
useGpgCmd()
sign(publishing.publications["revanced-patches-publication"])
}

View File

@@ -1,9 +0,0 @@
plugins {
id("java")
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}

View File

@@ -1,9 +0,0 @@
package android.os;
import java.io.File;
public final class Environment {
public static File getExternalStorageDirectory() {
throw new UnsupportedOperationException("Stub");
}
}

View File

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

View File

@@ -1,9 +1,10 @@
[versions]
revanced-patcher = "19.2.0"
smali = "3.0.3"
revanced-patcher = "19.3.1"
smali = "3.0.4"
guava = "33.0.0-jre"
gson = "2.10.1"
binary-compatibility-validator = "0.13.2"
binary-compatibility-validator = "0.14.0"
kotlin = "1.9.22"
[libraries]
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
@@ -13,3 +14,4 @@ gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
[plugins]
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }

View File

@@ -1,8 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStorePath=wrapper/dist

280
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.9.1",
"semantic-release": "^23.0.0"
"semantic-release": "^23.0.2"
}
},
"node_modules/@babel/code-frame": {
@@ -326,9 +326,9 @@
}
},
"node_modules/@octokit/request": {
"version": "8.1.6",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz",
"integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==",
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.2.0.tgz",
"integrity": "sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==",
"dev": true,
"dependencies": {
"@octokit/endpoint": "^9.0.0",
@@ -564,6 +564,26 @@
"node": ">= 16"
}
},
"node_modules/@saithodev/semantic-release-backmerge/node_modules/marked-terminal": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.2.0.tgz",
"integrity": "sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==",
"dev": true,
"dependencies": {
"ansi-escapes": "^6.2.0",
"cardinal": "^2.1.1",
"chalk": "^5.3.0",
"cli-table3": "^0.6.3",
"node-emoji": "^2.1.3",
"supports-hyperlinks": "^3.0.0"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"marked": ">=1 <12"
}
},
"node_modules/@saithodev/semantic-release-backmerge/node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
@@ -1195,9 +1215,9 @@
}
},
"node_modules/@sindresorhus/merge-streams": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz",
"integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==",
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.2.0.tgz",
"integrity": "sha512-UTce8mUwUW0RikMb/eseJ7ys0BRkZVFB86orHzrfW12ZmFtym5zua8joZ4L7okH2dDFHkcFjqnZ5GocWBXOFtA==",
"dev": true,
"engines": {
"node": ">=18"
@@ -1282,6 +1302,12 @@
"integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
"dev": true
},
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -1376,6 +1402,81 @@
"node": ">=6"
}
},
"node_modules/cli-highlight": {
"version": "2.1.11",
"resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz",
"integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
"highlight.js": "^10.7.1",
"mz": "^2.4.0",
"parse5": "^5.1.1",
"parse5-htmlparser2-tree-adapter": "^6.0.0",
"yargs": "^16.0.0"
},
"bin": {
"highlight": "bin/highlight"
},
"engines": {
"node": ">=8.0.0",
"npm": ">=5.0.0"
}
},
"node_modules/cli-highlight/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/cli-highlight/node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^7.0.0"
}
},
"node_modules/cli-highlight/node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"dev": true,
"dependencies": {
"cliui": "^7.0.2",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/cli-highlight/node_modules/yargs-parser": {
"version": "20.2.9",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
"dev": true,
"engines": {
"node": ">=10"
}
},
"node_modules/cli-table3": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
@@ -1818,9 +1919,9 @@
}
},
"node_modules/escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
"dev": true,
"engines": {
"node": ">=6"
@@ -1888,9 +1989,9 @@
}
},
"node_modules/fastq": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
"integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
"dev": true,
"dependencies": {
"reusify": "^1.0.4"
@@ -2052,12 +2153,12 @@
}
},
"node_modules/globby": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz",
"integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==",
"version": "14.0.1",
"resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz",
"integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==",
"dev": true,
"dependencies": {
"@sindresorhus/merge-streams": "^1.0.0",
"@sindresorhus/merge-streams": "^2.1.0",
"fast-glob": "^3.3.2",
"ignore": "^5.2.4",
"path-type": "^5.0.0",
@@ -2142,9 +2243,9 @@
}
},
"node_modules/hasown": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
"integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
@@ -2153,6 +2254,15 @@
"node": ">= 0.4"
}
},
"node_modules/highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
"dev": true,
"engines": {
"node": "*"
}
},
"node_modules/hook-std": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz",
@@ -2178,9 +2288,9 @@
}
},
"node_modules/http-proxy-agent": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz",
"integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.1.tgz",
"integrity": "sha512-My1KCEPs6A0hb4qCVzYp8iEvA8j8YqcvXLZZH8C9OFuTYpYjHE7N2dtG3mRl1HMD4+VGXpF3XcDVcxGBT7yDZQ==",
"dev": true,
"dependencies": {
"agent-base": "^7.1.0",
@@ -2191,9 +2301,9 @@
}
},
"node_modules/https-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz",
"integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==",
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.3.tgz",
"integrity": "sha512-kCnwztfX0KZJSLOBrcL0emLeFako55NWMovvyPP2AjsghNk9RB1yjSI+jVumPHYZsNXegNoqupSW9IY3afSH8w==",
"dev": true,
"dependencies": {
"agent-base": "^7.0.2",
@@ -2213,9 +2323,9 @@
}
},
"node_modules/ignore": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
"dev": true,
"engines": {
"node": ">= 4"
@@ -2629,9 +2739,9 @@
}
},
"node_modules/marked": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/marked/-/marked-11.1.1.tgz",
"integrity": "sha512-EgxRjgK9axsQuUa/oKMx5DEY8oXpKJfk61rT5iY3aRlgU6QJtUcxU5OAymdhCvWvhYcd9FKmO5eQoX8m9VGJXg==",
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-12.0.0.tgz",
"integrity": "sha512-Vkwtq9rLqXryZnWaQc86+FHLC6tr/fycMfYAhiOIXkrNmeGAyhSxjqu0Rs1i0bBqw5u0S7+lV9fdH2ZSVaoa0w==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
@@ -2641,14 +2751,14 @@
}
},
"node_modules/marked-terminal": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.2.0.tgz",
"integrity": "sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.0.0.tgz",
"integrity": "sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==",
"dev": true,
"dependencies": {
"ansi-escapes": "^6.2.0",
"cardinal": "^2.1.1",
"chalk": "^5.3.0",
"cli-highlight": "^2.1.11",
"cli-table3": "^0.6.3",
"node-emoji": "^2.1.3",
"supports-hyperlinks": "^3.0.0"
@@ -2657,7 +2767,7 @@
"node": ">=16.0.0"
},
"peerDependencies": {
"marked": ">=1 <12"
"marked": ">=1 <13"
}
},
"node_modules/meow": {
@@ -2739,6 +2849,17 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"dev": true,
"dependencies": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
"thenify-all": "^1.0.0"
}
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -5551,6 +5672,15 @@
"inBundle": true,
"license": "ISC"
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -5695,6 +5825,27 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
"dev": true
},
"node_modules/parse5-htmlparser2-tree-adapter": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
"dev": true,
"dependencies": {
"parse5": "^6.0.1"
}
},
"node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
"dev": true
},
"node_modules/parsimmon": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz",
@@ -5860,9 +6011,9 @@
}
},
"node_modules/read-pkg-up/node_modules/type-fest": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz",
"integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==",
"version": "4.10.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz",
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==",
"dev": true,
"engines": {
"node": ">=16"
@@ -5889,9 +6040,9 @@
}
},
"node_modules/read-pkg/node_modules/type-fest": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz",
"integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==",
"version": "4.10.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz",
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==",
"dev": true,
"engines": {
"node": ">=16"
@@ -5994,9 +6145,9 @@
"dev": true
},
"node_modules/semantic-release": {
"version": "23.0.0",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.0.tgz",
"integrity": "sha512-Jz7jEWO2igTtske112gC4PPE2whCMVrsgxUPG3/SZI7VE357suIUZFlJd1Yu0g2I6RPc2HxNEfUg7KhmDTjwqg==",
"version": "23.0.2",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.2.tgz",
"integrity": "sha512-OnVYJ6Xgzwe1x8MKswba7RU9+5djS1MWRTrTn5qsq3xZYpslroZkV9Pt0dA2YcIuieeuSZWJhn+yUWoBUHO5Fw==",
"dev": true,
"dependencies": {
"@semantic-release/commit-analyzer": "^11.0.0",
@@ -6017,8 +6168,8 @@
"hosted-git-info": "^7.0.0",
"import-from-esm": "^1.3.1",
"lodash-es": "^4.17.21",
"marked": "^11.0.0",
"marked-terminal": "^6.0.0",
"marked": "^12.0.0",
"marked-terminal": "^7.0.0",
"micromatch": "^4.0.2",
"p-each-series": "^3.0.0",
"p-reduce": "^3.0.0",
@@ -6247,9 +6398,9 @@
}
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
@@ -6481,9 +6632,9 @@
}
},
"node_modules/spdx-license-ids": {
"version": "3.0.16",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz",
"integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==",
"version": "3.0.17",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz",
"integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==",
"dev": true
},
"node_modules/split2": {
@@ -6655,6 +6806,27 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"dev": true,
"dependencies": {
"any-promise": "^1.0.0"
}
},
"node_modules/thenify-all": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
"dev": true,
"dependencies": {
"thenify": ">= 3.1.0 < 4"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",

View File

@@ -4,6 +4,6 @@
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.9.1",
"semantic-release": "^23.0.0"
"semantic-release": "^23.0.2"
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,3 @@
include("dummy")
rootProject.name = "revanced-patches"
buildCache {

View File

@@ -1,11 +1,11 @@
package app.revanced.meta
package app.revanced.generator
import app.revanced.patcher.PatchSet
import app.revanced.patcher.patch.Patch
import com.google.gson.GsonBuilder
import java.io.File
internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
internal class JsonPatchesFileGenerator : PatchesFileGenerator {
override fun generate(patches: PatchSet) = patches.map {
JsonPatch(
it.name!!,
@@ -20,9 +20,9 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
option.values,
option.title,
option.description,
option.required
option.required,
)
}
},
)
}.let {
File("patches.json").writeText(GsonBuilder().serializeNulls().create().toJson(it))
@@ -35,7 +35,7 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
val compatiblePackages: Set<Patch.CompatiblePackage>? = null,
val use: Boolean = true,
val requiresIntegrations: Boolean = false,
val options: List<Option>
val options: List<Option>,
) {
class Option(
val key: String,
@@ -46,4 +46,4 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
val required: Boolean,
)
}
}
}

View File

@@ -0,0 +1,12 @@
package app.revanced.generator
import app.revanced.patcher.PatchBundleLoader
import java.io.File
internal fun main() = PatchBundleLoader.Jar(
File("build/libs/").listFiles { it -> it.name.endsWith(".jar") }!!.first(),
).also { loader ->
if (loader.isEmpty()) throw IllegalStateException("No patches found")
}.let { bundle ->
arrayOf(JsonPatchesFileGenerator()).forEach { generator -> generator.generate(bundle) }
}

View File

@@ -0,0 +1,7 @@
package app.revanced.generator
import app.revanced.patcher.PatchSet
internal interface PatchesFileGenerator {
fun generate(patches: PatchSet)
}

View File

@@ -1,20 +0,0 @@
package app.revanced.meta
import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.PatchSet
import java.io.File
internal interface IPatchesFileGenerator {
fun generate(patches: PatchSet)
private companion object {
@JvmStatic
fun main(args: Array<String>) = PatchBundleLoader.Jar(
File("build/libs/").listFiles { it -> it.name.endsWith(".jar") }!!.first()
).also { loader ->
if (loader.isEmpty()) throw IllegalStateException("No patches found")
}.let { bundle ->
arrayOf(JsonPatchesFileGenerator()).forEach { generator -> generator.generate(bundle) }
}
}
}

View File

@@ -7,29 +7,34 @@ import app.revanced.patcher.patch.annotation.Patch
@Patch(
name = "Export all activities",
description = "Makes all app activities exportable.",
use = false
use = false,
)
@Suppress("unused")
object ExportAllActivitiesPatch : ResourcePatch() {
private const val EXPORTED_FLAG = "android:exported"
override fun execute(context: ResourceContext) {
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val activities = document.getElementsByTagName("activity")
for(i in 0..activities.length) {
for (i in 0..activities.length) {
activities.item(i)?.apply {
val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG)
if (exportedAttribute != null) {
if (exportedAttribute.nodeValue != "true")
if (exportedAttribute.nodeValue != "true") {
exportedAttribute.nodeValue = "true"
}
}
// Reason why the attribute is added in the case it does not exist:
// https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604
else document.createAttribute(EXPORTED_FLAG)
.apply { value = "true" }
.let(attributes::setNamedItem)
else {
document.createAttribute(EXPORTED_FLAG)
.apply { value = "true" }
.let(attributes::setNamedItem)
}
}
}
}

View File

@@ -7,7 +7,7 @@ import app.revanced.patcher.patch.annotation.Patch
@Patch(
name = "Predictive back gesture",
description = "Enables the predictive back gesture introduced on Android 13.",
use = false
use = false,
)
@Suppress("unused")
object PredictiveBackGesturePatch : ResourcePatch() {

View File

@@ -8,16 +8,18 @@ import org.w3c.dom.Element
@Patch(
name = "Enable Android debugging",
description = "Enables Android debugging capabilities. This can slow down the app.",
use = false
use = false,
)
@Suppress("unused")
object EnableAndroidDebuggingPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
context.xmlEditor["AndroidManifest.xml"].use { dom ->
val applicationNode = dom
.file
.getElementsByTagName("application")
.item(0) as Element
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode =
document
.getElementsByTagName("application")
.item(0) as Element
// set application as debuggable
applicationNode.setAttribute("android:debuggable", "true")

View File

@@ -11,16 +11,17 @@ import java.io.File
name = "Override certificate pinning",
description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.",
dependencies = [EnableAndroidDebuggingPatch::class],
use = false
use = false,
)
@Suppress("unused")
object OverrideCertificatePinningPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
val resXmlDirectory = context["res/xml"]
val resXmlDirectory = context.get("res/xml")
// Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist.
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode = document.getElementsByTagName("application").item(0) as Element
if (!applicationNode.hasAttribute("networkSecurityConfig")) {
@@ -54,7 +55,7 @@ object OverrideCertificatePinningPatch : ResourcePatch() {
</trust-anchors>
</debug-overrides>
</network-security-config>
"""
""",
)
} else {
// If the file already exists.
@@ -63,12 +64,11 @@ object OverrideCertificatePinningPatch : ResourcePatch() {
writeText(
text.replace(
"<trust-anchors>",
"<trust-anchors>\n<certificates src=\"user\" overridePins=\"true\" />\n<certificates src=\"system\" />"
)
"<trust-anchors>\n<certificates src=\"user\" overridePins=\"true\" />\n<certificates src=\"system\" />",
),
)
}
}
}
}
}

View File

@@ -11,20 +11,21 @@ import java.io.Closeable
@Patch(
name = "Change package name",
description = "Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.",
use = false
use = false,
)
@Suppress("unused")
object ChangePackageNamePatch : ResourcePatch(), Closeable {
private val packageNameOption = stringPatchOption(
key = "packageName",
default = "Default",
values = mapOf("Default" to "Default"),
title = "Package name",
description = "The name of the package to rename the app to.",
required = true
) {
it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$"))
}
private val packageNameOption =
stringPatchOption(
key = "packageName",
default = "Default",
values = mapOf("Default" to "Default"),
title = "Package name",
description = "The name of the package to rename the app to.",
required = true,
) {
it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$"))
}
private lateinit var context: ResourceContext
@@ -43,20 +44,27 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable {
fun setOrGetFallbackPackageName(fallbackPackageName: String): String {
val packageName = packageNameOption.value!!
return if (packageName == packageNameOption.default)
return if (packageName == packageNameOption.default) {
fallbackPackageName.also { packageNameOption.value = it }
else
} else {
packageName
}
}
override fun close() = context.xmlEditor["AndroidManifest.xml"].use { editor ->
val replacementPackageName = packageNameOption.value
override fun close() =
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
manifest.setAttribute(
"package",
if (replacementPackageName != packageNameOption.default) replacementPackageName
else "${manifest.getAttribute("package")}.revanced"
)
}
val replacementPackageName = packageNameOption.value
val manifest = document.getElementsByTagName("manifest").item(0) as Element
manifest.setAttribute(
"package",
if (replacementPackageName != packageNameOption.default) {
replacementPackageName
} else {
"${manifest.getAttribute("package")}.revanced"
},
)
}
}

View File

@@ -19,6 +19,7 @@ import java.util.*
* An identifier of an app. For example, `youtube`.
*/
private typealias AppId = String
/**
* An identifier of a patch. For example, `ad.general.HideAdsPatch`.
*/
@@ -28,10 +29,12 @@ private typealias PatchId = String
* A set of resources of a patch.
*/
private typealias PatchResources = MutableSet<BaseResource>
/**
* A map of resources belonging to a patch.
*/
private typealias AppResources = MutableMap<PatchId, PatchResources>
/**
* A map of resources belonging to an app.
*/
@@ -67,40 +70,44 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
override fun execute(context: ResourceContext) {
this.context = context
resources = buildMap {
/**
* Puts resources under `/resources/addresources/<value>/<resourceKind>.xml` into the map.
*
* @param value The value of the resource. For example, `values` or `values-de`.
* @param resourceKind The kind of the resource. For example, `strings` or `arrays`.
* @param transform A function that transforms the [Node]s from the XML files to a [BaseResource].
*/
fun addResources(
value: Value,
resourceKind: String,
transform: (Node) -> BaseResource,
) {
inputStreamFromBundledResource(
"addresources",
"$value/$resourceKind.xml"
)?.let { stream ->
// Add the resources associated with the given value to the map,
// instead of overwriting it.
// This covers the example case such as adding strings and arrays of the same value.
getOrPut(value, ::mutableMapOf).apply {
context.xmlEditor[stream].use {
it.file.getElementsByTagName("app").asSequence().forEach { app ->
val appId = app.attributes.getNamedItem("id").textContent
resources =
buildMap {
/**
* Puts resources under `/resources/addresources/<value>/<resourceKind>.xml` into the map.
*
* @param value The value of the resource. For example, `values` or `values-de`.
* @param resourceKind The kind of the resource. For example, `strings` or `arrays`.
* @param transform A function that transforms the [Node]s from the XML files to a [BaseResource].
*/
fun addResources(
value: Value,
resourceKind: String,
transform: (Node) -> BaseResource,
) {
inputStreamFromBundledResource(
"addresources",
"$value/$resourceKind.xml",
)?.let { stream ->
// Add the resources associated with the given value to the map,
// instead of overwriting it.
// This covers the example case such as adding strings and arrays of the same value.
getOrPut(value, ::mutableMapOf).apply {
context.xmlEditor[stream].use { editor ->
val document = editor.file
getOrPut(appId, ::mutableMapOf).apply {
app.forEachChildElement { patch ->
val patchId = patch.attributes.getNamedItem("id").textContent
document.getElementsByTagName("app").asSequence().forEach { app ->
val appId = app.attributes.getNamedItem("id").textContent
getOrPut(patchId, ::mutableSetOf).apply {
patch.forEachChildElement { resourceNode ->
val resource = transform(resourceNode)
getOrPut(appId, ::mutableMapOf).apply {
app.forEachChildElement { patch ->
val patchId = patch.attributes.getNamedItem("id").textContent
add(resource)
getOrPut(patchId, ::mutableSetOf).apply {
patch.forEachChildElement { resourceNode ->
val resource = transform(resourceNode)
add(resource)
}
}
}
}
@@ -109,23 +116,22 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
}
}
}
}
// Stage all resources to a temporary map.
// Staged resources consumed by AddResourcesPatch#invoke(PatchClass)
// are later used in AddResourcesPatch#close.
try {
val addStringResources = { value: Value ->
addResources(value, "strings", StringResource::fromNode)
// Stage all resources to a temporary map.
// Staged resources consumed by AddResourcesPatch#invoke(PatchClass)
// are later used in AddResourcesPatch#close.
try {
val addStringResources = { value: Value ->
addResources(value, "strings", StringResource::fromNode)
}
Locale.getISOLanguages().asSequence().map { "values-$it" }.forEach { addStringResources(it) }
addStringResources("values")
addResources("values", "arrays", ArrayResource::fromNode)
} catch (e: Exception) {
throw PatchException("Failed to read resources", e)
}
Locale.getISOLanguages().asSequence().map { "values-$it" }.forEach { addStringResources(it) }
addStringResources("values")
addResources("values", "arrays", ArrayResource::fromNode)
} catch (e: Exception) {
throw PatchException("Failed to read resources", e)
}
}
}
/**
@@ -136,8 +142,10 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
*
* @return True if the resource was added, false if it already existed.
*/
operator fun invoke(value: Value, resource: BaseResource) =
getOrPut(value, ::mutableSetOf).add(resource)
operator fun invoke(
value: Value,
resource: BaseResource,
) = getOrPut(value, ::mutableSetOf).add(resource)
/**
* Adds a list of [BaseResource]s to the map using [MutableMap.getOrPut].
@@ -147,8 +155,10 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
*
* @return True if the resources were added, false if they already existed.
*/
operator fun invoke(value: Value, resources: Iterable<BaseResource>) =
getOrPut(value, ::mutableSetOf).addAll(resources)
operator fun invoke(
value: Value,
resources: Iterable<BaseResource>,
) = getOrPut(value, ::mutableSetOf).addAll(resources)
/**
* Adds a [StringResource].
@@ -177,10 +187,9 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
*/
operator fun invoke(
name: String,
items: List<String>
items: List<String>,
) = invoke("values", ArrayResource(name, items))
/**
* Puts all resources of any [Value] staged in [resources] for the given [PatchClass] to [AddResourcesPatch].
*
@@ -209,7 +218,7 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
appId to patchId
}
}
},
): Boolean {
val (appId, patchId) = patch.parseIds()
@@ -218,7 +227,7 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
// Stage resources for the given patch to AddResourcesPatch associated with their value.
resources.forEach { (value, resources) ->
resources[appId]?.get(patchId)?.let { patchResources ->
if (invoke(value, patchResources)) result = true
if (invoke(value, patchResources)) result = true
}
}
@@ -232,28 +241,32 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
override fun close() {
operator fun MutableMap<String, Pair<DomFileEditor, Node>>.invoke(
value: Value,
resource: BaseResource
resource: BaseResource,
) {
// TODO: Fix open-closed principle violation by modifying BaseResource#serialize so that it accepts
// a Value and the map of editors. It will then get or put the editor suitable for its resource type
// a Value and the map of documents. It will then get or put the document suitable for its resource type
// to serialize itself to it.
val resourceFileName = when (resource) {
is StringResource -> "strings"
is ArrayResource -> "arrays"
else -> throw NotImplementedError("Unsupported resource type")
}
getOrPut(resourceFileName) {
val targetFile = context["res/$value/$resourceFileName.xml"].also {
it.parentFile?.mkdirs()
it.createNewFile()
val resourceFileName =
when (resource) {
is StringResource -> "strings"
is ArrayResource -> "arrays"
else -> throw NotImplementedError("Unsupported resource type")
}
getOrPut(resourceFileName) {
val targetFile =
context.get("res/$value/$resourceFileName.xml").also {
it.parentFile?.mkdirs()
it.createNewFile()
}
context.xmlEditor[targetFile.path].let { editor ->
val document = editor.file
// Save the target node here as well
// in order to avoid having to call editor.getNode("resources")
// every time addUsingEditors is called but also save the editor so that it can be closed later.
editor to editor.getNode("resources")
// in order to avoid having to call document.getNode("resources")
// but also save the document so that it can be closed later.
editor to document.getNode("resources")
}
}.let { (_, targetNode) ->
targetNode.addResource(resource) { invoke(value, it) }
@@ -261,17 +274,17 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
}
forEach { (value, resources) ->
// A map of editors associated by their kind (e.g. strings, arrays).
// Each editor is accompanied by the target node to which resources are added.
// A map is used because Map#getOrPut allows opening a new editor for the duration of a resource value.
// A map of document associated by their kind (e.g. strings, arrays).
// Each document is accompanied by the target node to which resources are added.
// A map is used because Map#getOrPut allows opening a new document for the duration of a resource value.
// This is done to prevent having to open the files for every resource that is added.
// Instead, it is cached once and reused for resources of the same value.
// This map is later accessed to close all editors for the current resource value.
val resourceFileEditors = mutableMapOf<String, Pair<DomFileEditor, Node>>()
// This map is later accessed to close all documents for the current resource value.
val documents = mutableMapOf<String, Pair<DomFileEditor, Node>>()
resources.forEach { resource -> resourceFileEditors(value, resource) }
resources.forEach { resource -> documents(value, resource) }
resourceFileEditors.values.forEach { (editor, _) -> editor.close() }
documents.values.forEach { (document, _) -> document.close() }
}
}
}

View File

@@ -9,12 +9,12 @@ import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
@Suppress("MemberVisibilityCanBePrivate")
abstract class BaseTransformInstructionsPatch<T> : BytecodePatch() {
abstract class BaseTransformInstructionsPatch<T> : BytecodePatch(emptySet()) {
abstract fun filterMap(
classDef: ClassDef,
method: Method,
instruction: Instruction,
instructionIndex: Int
instructionIndex: Int,
): T?
abstract fun transform(mutableMethod: MutableMethod, entry: T)

View File

@@ -8,16 +8,17 @@ import org.w3c.dom.Element
@Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.")
internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
// create an xml editor instance
context.xmlEditor["AndroidManifest.xml"].use { dom ->
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
// get the application node
val applicationNode = dom
.file
.getElementsByTagName("application")
.item(0) as Element
val applicationNode =
document
.getElementsByTagName("application")
.item(0) as Element
// set allowAudioPlaybackCapture attribute to true
applicationNode.setAttribute("android:allowAudioPlaybackCapture", "true")
}
}
}
}

View File

@@ -1,51 +0,0 @@
package app.revanced.patches.music.audio.exclusiveaudio.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
internal object ExclusiveAudioFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L", "Z"),
listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQ,
Opcode.CONST_4,
Opcode.GOTO,
Opcode.NOP,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.IF_EQZ,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.INVOKE_INTERFACE,
Opcode.GOTO,
Opcode.RETURN_VOID
)
)

View File

@@ -1,14 +1,12 @@
package app.revanced.patches.music.misc.gms.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object ServiceCheckFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.STATIC,
listOf("L", "I"),
strings = listOf("Google Play Services not available")
strings = listOf("Google Play Services not available"),
)

View File

@@ -6,8 +6,5 @@ import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
@Patch(requiresIntegrations = true)
object IntegrationsPatch : BaseIntegrationsPatch(
"Lapp/revanced/integrations/utils/ReVancedUtils;",
setOf(
ApplicationInitFingerprint,
),
setOf(ApplicationInitFingerprint),
)

View File

@@ -6,23 +6,24 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import org.w3c.dom.Element
@Patch(
name = "Remove broadcasts restriction",
description = "Enables starting/stopping NetGuard via broadcasts.",
compatiblePackages = [CompatiblePackage("eu.faircode.netguard")],
use = false
use = false,
)
@Suppress("unused")
object RemoveBroadcastsRestrictionPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
context.xmlEditor["AndroidManifest.xml"].use { dom ->
val applicationNode = dom
.file
.getElementsByTagName("application")
.item(0) as Element
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
applicationNode.getElementsByTagName("receiver").also { list ->
val applicationNode =
document
.getElementsByTagName("application")
.item(0) as Element
applicationNode.getElementsByTagName("receiver").also { list ->
for (i in 0 until list.length) {
val element = list.item(i) as? Element ?: continue
if (element.getAttribute("android:name") == "eu.faircode.netguard.WidgetAdmin") {

View File

@@ -0,0 +1,115 @@
package app.revanced.patches.openinghours.misc.fix.crash
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.extensions.newLabel
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.openinghours.misc.fix.crash.fingerprints.SetPlaceFingerprint
import app.revanced.util.exception
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21t
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch(
name = "Fix crash",
compatiblePackages = [CompatiblePackage("de.simon.openinghours", ["1.0"])],
)
@Suppress("unused")
object FixCrashPatch : BytecodePatch(
setOf(SetPlaceFingerprint),
) {
override fun execute(context: BytecodeContext) {
SetPlaceFingerprint.result?.let {
val indexedInstructions = it.mutableMethod.getInstructions().withIndex().toList()
/**
* This function replaces all `checkNotNull` instructions in the integer interval
* from [startIndex] to [endIndex], both inclusive. In place of the `checkNotNull`
* instruction an if-null check is inserted. If the if-null check yields that
* the value is indeed null, we jump to a newly created label at `endIndex + 1`.
*/
fun avoidNullPointerException(startIndex: Int, endIndex: Int) {
val continueLabel = it.mutableMethod.newLabel(endIndex + 1)
for (index in startIndex..endIndex) {
val instruction = indexedInstructions[index].value
if (!instruction.isCheckNotNullInstruction) {
continue
}
val checkNotNullInstruction = instruction as FiveRegisterInstruction
val originalRegister = checkNotNullInstruction.registerC
it.mutableMethod.replaceInstruction(
index,
BuilderInstruction21t(
Opcode.IF_EQZ,
originalRegister,
continueLabel,
),
)
}
}
val getOpeningHoursIndex = getIndicesOfInvoke(
indexedInstructions,
"Lde/simon/openinghours/models/Place;",
"getOpeningHours",
)
val setWeekDayTextIndex = getIndexOfInvoke(
indexedInstructions,
"Lde/simon/openinghours/views/custom/PlaceCard;",
"setWeekDayText",
)
val startCalculateStatusIndex = getIndexOfInvoke(
indexedInstructions,
"Lde/simon/openinghours/views/custom/PlaceCard;",
"startCalculateStatus",
)
// Replace the Intrinsics;->checkNotNull instructions with a null check
// and jump to our newly created label if it returns true.
// This avoids the NullPointerExceptions.
avoidNullPointerException(getOpeningHoursIndex[1], startCalculateStatusIndex)
avoidNullPointerException(getOpeningHoursIndex[0], setWeekDayTextIndex)
} ?: throw SetPlaceFingerprint.exception
}
private fun isInvokeInstruction(instruction: Instruction, className: String, methodName: String): Boolean {
val methodRef = instruction.getReference<MethodReference>() ?: return false
return methodRef.definingClass == className && methodRef.name == methodName
}
private fun getIndicesOfInvoke(
instructions: List<IndexedValue<Instruction>>,
className: String,
methodName: String,
): List<Int> = instructions.mapNotNull { (index, instruction) ->
if (isInvokeInstruction(instruction, className, methodName)) {
index
} else {
null
}
}
private fun getIndexOfInvoke(
instructions: List<IndexedValue<Instruction>>,
className: String,
methodName: String,
): Int = instructions.first { (_, instruction) ->
isInvokeInstruction(instruction, className, methodName)
}.index
private val Instruction.isCheckNotNullInstruction
get() = isInvokeInstruction(this, "Lkotlin/jvm/internal/Intrinsics;", "checkNotNull")
}

View File

@@ -0,0 +1,12 @@
package app.revanced.patches.openinghours.misc.fix.crash.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object SetPlaceFingerprint : MethodFingerprint(
"V",
parameters = listOf("Lde/simon/openinghours/models/Place;"),
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "Lde/simon/openinghours/views/custom/PlaceCard;" &&
methodDef.name == "setPlace"
},
)

View File

@@ -9,8 +9,10 @@ object HideBannerPatch : ResourcePatch() {
private const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml"
override fun execute(context: ResourceContext) {
context.xmlEditor[RESOURCE_FILE_PATH].use {
it.file.getElementsByTagName("merge").item(0).childNodes.apply {
context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
val document = editor.file
document.getElementsByTagName("merge").item(0).childNodes.apply {
val attributes = arrayOf("height", "width")
for (i in 1 until length) {
@@ -30,4 +32,3 @@ object HideBannerPatch : ResourcePatch() {
}
}
}

View File

@@ -5,6 +5,7 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.reddit.customclients.infinityforreddit.api.SpoofClientPatch
import app.revanced.patches.reddit.customclients.infinityforreddit.subscription.fingerprints.BillingClientOnServiceConnected
import app.revanced.patches.reddit.customclients.infinityforreddit.subscription.fingerprints.StartSubscriptionActivityFingerprint
import app.revanced.util.returnEarly
@@ -12,13 +13,14 @@ import app.revanced.util.returnEarly
name = "Unlock subscription",
description = "Unlocks the subscription feature but requires a custom client ID.",
compatiblePackages = [
CompatiblePackage("ml.docilealligator.infinityforreddit")
CompatiblePackage("ml.docilealligator.infinityforreddit"),
],
dependencies = [SpoofClientPatch::class]
dependencies = [SpoofClientPatch::class],
)
@Suppress("unused")
object UnlockSubscriptionPatch : BytecodePatch(
setOf(StartSubscriptionActivityFingerprint)
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected),
) {
override fun execute(context: BytecodeContext) = listOf(StartSubscriptionActivityFingerprint).returnEarly()
override fun execute(context: BytecodeContext) =
listOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
}

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.subscription.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object BillingClientOnServiceConnected : MethodFingerprint(
strings = listOf("Billing service connected"),
)

View File

@@ -0,0 +1,32 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.LinkHelperOpenLinkFingerprint
import app.revanced.util.exception
@Patch(
name = "Fix /s/ links",
description = "Fixes the issue where /s/ links do not work.",
compatiblePackages = [
CompatiblePackage("com.laurencedawson.reddit_sync"),
CompatiblePackage("com.laurencedawson.reddit_sync.pro"),
CompatiblePackage("com.laurencedawson.reddit_sync.dev")
],
requiresIntegrations = true
)
object FixSLinksPatch : BytecodePatch(
setOf(LinkHelperOpenLinkFingerprint)
) {
override fun execute(context: BytecodeContext) =
LinkHelperOpenLinkFingerprint.result?.mutableMethod?.addInstructions(
1,
"""
invoke-static { p3 }, Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;->resolveSLink(Ljava/lang/String;)Ljava/lang/String;
move-result-object p3
"""
) ?: throw LinkHelperOpenLinkFingerprint.exception
}

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object LinkHelperOpenLinkFingerprint: MethodFingerprint(
strings = listOf("Link title: ")
)

View File

@@ -22,19 +22,21 @@ abstract class BaseGmsCoreSupportResourcePatch(
private val fromPackageName: String,
private val toPackageName: String,
private val spoofedPackageSignature: String,
dependencies: Set<PatchClass> = setOf()
dependencies: Set<PatchClass> = setOf(),
) : ResourcePatch(dependencies = setOf(ChangePackageNamePatch::class, AddResourcesPatch::class) + dependencies) {
internal val gmsCoreVendorOption = stringPatchOption(
key = "gmsCoreVendor",
default = "com.mgoogle",
values = mapOf(
"Vanced" to "com.mgoogle",
"ReVanced" to "app.revanced"
),
title = "GmsCore Vendor",
description = "The group id of the GmsCore vendor.",
required = true
) { it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) }
internal val gmsCoreVendorOption =
stringPatchOption(
key = "gmsCoreVendor",
default = "com.mgoogle",
values =
mapOf(
"Vanced" to "com.mgoogle",
"ReVanced" to "app.revanced",
),
title = "GmsCore Vendor",
description = "The group id of the GmsCore vendor.",
required = true,
) { it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) }
protected val gmsCoreVendor by gmsCoreVendorOption
@@ -49,17 +51,22 @@ abstract class BaseGmsCoreSupportResourcePatch(
* Add metadata to manifest to support spoofing the package name and signature of GmsCore.
*/
private fun ResourceContext.addSpoofingMetadata() {
fun Node.adoptChild(tagName: String, block: Element.() -> Unit) {
fun Node.adoptChild(
tagName: String,
block: Element.() -> Unit,
) {
val child = ownerDocument.createElement(tagName)
child.block()
appendChild(child)
}
xmlEditor["AndroidManifest.xml"].use {
val applicationNode = it
.file
.getElementsByTagName("application")
.item(0)
xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode =
document
.getElementsByTagName("application")
.item(0)
// Spoof package name and signature.
applicationNode.adoptChild("meta-data") {
@@ -87,27 +94,27 @@ abstract class BaseGmsCoreSupportResourcePatch(
private fun ResourceContext.patchManifest() {
val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName)
val manifest = this["AndroidManifest.xml"].readText()
this["AndroidManifest.xml"].writeText(
val manifest = this.get("AndroidManifest.xml").readText()
this.get("AndroidManifest.xml").writeText(
manifest.replace(
"package=\"$fromPackageName",
"package=\"$packageName"
"package=\"$packageName",
).replace(
"android:authorities=\"$fromPackageName",
"android:authorities=\"$packageName"
"android:authorities=\"$packageName",
).replace(
"$fromPackageName.permission.C2D_MESSAGE",
"$packageName.permission.C2D_MESSAGE"
"$packageName.permission.C2D_MESSAGE",
).replace(
"$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
"$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
"$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
).replace(
"com.google.android.c2dm",
"$gmsCoreVendor.android.c2dm"
"$gmsCoreVendor.android.c2dm",
).replace(
"</queries>",
"<package android:name=\"$gmsCoreVendor.android.gms\"/></queries>"
)
"<package android:name=\"$gmsCoreVendor.android.gms\"/></queries>",
),
)
}
}
}

View File

@@ -11,23 +11,25 @@ import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
abstract class BaseIntegrationsPatch(
private val hooks: Set<IntegrationsFingerprint>
private val hooks: Set<IntegrationsFingerprint>,
) : BytecodePatch(hooks) {
@Deprecated(
"Use the constructor without the integrationsDescriptor parameter",
ReplaceWith("AbstractIntegrationsPatch(hooks)")
ReplaceWith("BaseIntegrationsPatch(hooks)"),
)
@Suppress("UNUSED_PARAMETER")
constructor(
integrationsDescriptor: String,
hooks: Set<IntegrationsFingerprint>
hooks: Set<IntegrationsFingerprint>,
) : this(hooks)
override fun execute(context: BytecodeContext) {
if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) throw PatchException(
"Integrations have not been merged yet. This patch can not succeed without merging the integrations."
)
if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) {
throw PatchException(
"Integrations have not been merged yet. This patch can not succeed without merging the integrations.",
)
}
hooks.forEach { hook ->
hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR)
@@ -47,14 +49,14 @@ abstract class BaseIntegrationsPatch(
opcodes: Iterable<Opcode?>? = null,
strings: Iterable<String>? = null,
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {},
) : MethodFingerprint(
returnType,
accessFlags,
parameters,
opcodes,
strings,
customFingerprint
customFingerprint,
) {
fun invoke(integrationsDescriptor: String) {
result?.mutableMethod?.let { method ->
@@ -63,7 +65,7 @@ abstract class BaseIntegrationsPatch(
method.addInstruction(
0,
"sput-object v$contextRegister, " +
"$integrationsDescriptor->context:Landroid/content/Context;"
"$integrationsDescriptor->context:Landroid/content/Context;",
)
} ?: throw PatchException("Could not find hook target fingerprint.")
}
@@ -76,4 +78,4 @@ abstract class BaseIntegrationsPatch(
private companion object {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/shared/Utils;"
}
}
}

View File

@@ -7,7 +7,6 @@ import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
object ResourceMappingPatch : ResourcePatch() {
internal lateinit var resourceMappings: List<ResourceElement>
private set
@@ -17,7 +16,7 @@ object ResourceMappingPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
// save the file in memory to concurrently read from
val resourceXmlFile = context["res/values/public.xml"].readBytes()
val resourceXmlFile = context.get("res/values/public.xml").readBytes()
// create a synchronized list to store the resource mappings
val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
@@ -25,7 +24,9 @@ object ResourceMappingPatch : ResourcePatch() {
for (threadIndex in 0 until THREAD_COUNT) {
threadPoolExecutor.execute thread@{
context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
val resources = editor.file.documentElement.childNodes
val document = editor.file
val resources = document.documentElement.childNodes
val resourcesLength = resources.length
val jobSize = resourcesLength / THREAD_COUNT
@@ -59,4 +60,4 @@ object ResourceMappingPatch : ResourcePatch() {
}
data class ResourceElement(val type: String, val name: String, val id: Long)
}
}

View File

@@ -21,16 +21,18 @@ import java.io.Closeable
*/
abstract class BaseSettingsResourcePatch(
private val rootPreference: Pair<IntentPreference, String>? = null,
dependencies: Set<PatchClass> = emptySet()
dependencies: Set<PatchClass> = emptySet(),
) : ResourcePatch(
dependencies = setOf(AddResourcesPatch::class) + dependencies
), MutableSet<BasePreference> by mutableSetOf(), Closeable {
dependencies = setOf(AddResourcesPatch::class) + dependencies,
),
MutableSet<BasePreference> by mutableSetOf(),
Closeable {
private lateinit var context: ResourceContext
override fun execute(context: ResourceContext) {
context.copyResources(
"settings",
ResourceGroup("xml", "revanced_prefs.xml")
ResourceGroup("xml", "revanced_prefs.xml"),
)
this.context = context
@@ -49,14 +51,18 @@ abstract class BaseSettingsResourcePatch(
// Add the root preference to an existing fragment if needed.
rootPreference?.let { (intentPreference, fragment) ->
context.xmlEditor["res/xml/$fragment.xml"].use {
it.getNode("PreferenceScreen").addPreference(intentPreference)
context.xmlEditor["res/xml/$fragment.xml"].use { editor ->
val document = editor.file
document.getNode("PreferenceScreen").addPreference(intentPreference)
}
}
// Add all preferences to the ReVanced fragment.
context.xmlEditor["res/xml/revanced_prefs.xml"].use { editor ->
val revancedPreferenceScreenNode = editor.getNode("PreferenceScreen")
val document = editor.file
val revancedPreferenceScreenNode = document.getNode("PreferenceScreen")
forEach { revancedPreferenceScreenNode.addPreference(it) }
}
}

View File

@@ -10,7 +10,7 @@ import org.w3c.dom.Element
@Patch(
name = "Custom theme",
description = "Applies a custom theme.",
compatiblePackages = [CompatiblePackage("com.spotify.music")]
compatiblePackages = [CompatiblePackage("com.spotify.music")],
)
@Suppress("unused")
object CustomThemePatch : ResourcePatch() {
@@ -19,7 +19,7 @@ object CustomThemePatch : ResourcePatch() {
default = "@android:color/black",
title = "Primary background color",
description = "The background color. Can be a hex color or a resource reference.",
required = true
required = true,
)
private var backgroundColorSecondary by stringPatchOption(
@@ -27,7 +27,7 @@ object CustomThemePatch : ResourcePatch() {
default = "#ff282828",
title = "Secondary background color",
description = "The secondary background color. (e.g. search box, artist & podcast). Can be a hex color or a resource reference.",
required = true
required = true,
)
private var accentColor by stringPatchOption(
@@ -35,16 +35,17 @@ object CustomThemePatch : ResourcePatch() {
default = "#ff1ed760",
title = "Accent color",
description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.",
required = true
required = true,
)
private var accentColorPressed by stringPatchOption(
key = "accentColorPressed",
default = "#ff169c46",
title = "Pressed dark theme accent color",
description = "The color when accented buttons are pressed, by default slightly darker than accent. "
+ "Can be a hex color or a resource reference.",
required = true
description =
"The color when accented buttons are pressed, by default slightly darker than accent. " +
"Can be a hex color or a resource reference.",
required = true,
)
override fun execute(context: ResourceContext) {
@@ -54,23 +55,27 @@ object CustomThemePatch : ResourcePatch() {
val accentColorPressed = accentColorPressed!!
context.xmlEditor["res/values/colors.xml"].use { editor ->
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
val document = editor.file
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
for (i in 0 until resourcesNode.childNodes.length) {
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
node.textContent = when (node.getAttribute("name")) {
"dark_base_background_elevated_base", "design_dark_default_color_background",
"design_dark_default_color_surface", "gray_7", "gray_background", "gray_layer",
"sthlm_blk" -> backgroundColor
node.textContent =
when (node.getAttribute("name")) {
"dark_base_background_elevated_base", "design_dark_default_color_background",
"design_dark_default_color_surface", "gray_7", "gray_background", "gray_layer",
"sthlm_blk",
-> backgroundColor
"gray_15" -> backgroundColorSecondary
"gray_15" -> backgroundColorSecondary
"dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor
"dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor
"dark_brightaccent_background_press" -> accentColorPressed
else -> continue
}
"dark_brightaccent_background_press" -> accentColorPressed
else -> continue
}
}
}
}

View File

@@ -23,19 +23,19 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
dependencies = [IntegrationsPatch::class, SettingsPatch::class],
compatiblePackages = [
CompatiblePackage("com.ss.android.ugc.trill"),
CompatiblePackage("com.zhiliaoapp.musically")
CompatiblePackage("com.zhiliaoapp.musically"),
],
use = false
use = false,
)
@Suppress("unused")
object SpoofSimPatch : BytecodePatch() {
object SpoofSimPatch : BytecodePatch(emptySet()) {
private val replacements = hashMapOf(
"getSimCountryIso" to "getCountryIso",
"getNetworkCountryIso" to "getCountryIso",
"getSimOperator" to "getOperator",
"getNetworkOperator" to "getOperator",
"getSimOperatorName" to "getOperatorName",
"getNetworkOperatorName" to "getOperatorName"
"getNetworkOperatorName" to "getOperatorName",
)
override fun execute(context: BytecodeContext) {
@@ -85,7 +85,7 @@ object SpoofSimPatch : BytecodePatch() {
with(SettingsStatusLoadFingerprint.result!!.mutableMethod) {
addInstruction(
0,
"invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableSimSpoof()V"
"invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableSimSpoof()V",
)
}
}
@@ -99,7 +99,7 @@ object SpoofSimPatch : BytecodePatch() {
"""
invoke-static {v$resultReg}, Lapp/revanced/integrations/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$resultReg
"""
""",
)
}
}
}

View File

@@ -10,11 +10,11 @@ import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch
name = "Disable dashboard ads",
description = "Disables ads in the dashboard.",
compatiblePackages = [CompatiblePackage("com.tumblr")],
dependencies = [TimelineFilterPatch::class]
dependencies = [TimelineFilterPatch::class],
)
@Suppress("unused")
object DisableDashboardAds : BytecodePatch() {
override fun execute(context: BytecodeContext) {
object DisableDashboardAds : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
// The timeline object types are filtered by their name in the TimelineObjectType enum.
// This is often different from the "object_type" returned in the api (noted in comments here)
arrayOf(
@@ -29,9 +29,9 @@ object DisableDashboardAds : BytecodePatch() {
"DISPLAY_IO_INTERSCROLLER_AD", // "display_io_interscroller"
"DISPLAY_IO_HEADLINE_VIDEO_AD", // "display_io_headline_video"
"FACEBOOK_BIDDAABLE", // "facebook_biddable_sdk_ad"
"GOOGLE_NATIVE" // "google_native_ad"
"GOOGLE_NATIVE", // "google_native_ad"
).forEach {
TimelineFilterPatch.addObjectTypeFilter(it)
}
}
}
}

View File

@@ -10,13 +10,13 @@ import app.revanced.patches.tumblr.featureflags.OverrideFeatureFlagsPatch
name = "Disable in-app update",
description = "Disables the in-app update check and update prompt.",
dependencies = [OverrideFeatureFlagsPatch::class],
compatiblePackages = [CompatiblePackage("com.tumblr")]
compatiblePackages = [CompatiblePackage("com.tumblr")],
)
@Suppress("unused")
object DisableInAppUpdatePatch : BytecodePatch() {
object DisableInAppUpdatePatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
// Before checking for updates using Google Play core AppUpdateManager, the value of this feature flag is checked.
// If this flag is false or the last update check was today and no update check is performed.
OverrideFeatureFlagsPatch.addOverride("inAppUpdate", "false")
}
}
}

View File

@@ -11,10 +11,10 @@ import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch
name = "Disable Tumblr Live",
description = "Disable the Tumblr Live tab button and dashboard carousel.",
dependencies = [OverrideFeatureFlagsPatch::class, TimelineFilterPatch::class],
compatiblePackages = [CompatiblePackage("com.tumblr")]
compatiblePackages = [CompatiblePackage("com.tumblr")],
)
@Suppress("unused")
object DisableTumblrLivePatch : BytecodePatch() {
object DisableTumblrLivePatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
// Hide the LIVE_MARQUEE timeline element that appears in the feed
// Called "live_marquee" in api response
@@ -23,4 +23,4 @@ object DisableTumblrLivePatch : BytecodePatch() {
// Hide the Tab button for Tumblr Live by forcing the feature flag to false
OverrideFeatureFlagsPatch.addOverride("liveStreaming", "false")
}
}
}

View File

@@ -0,0 +1,83 @@
package app.revanced.patches.twitter.interaction.downloads
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.twitter.interaction.downloads.fingerprints.BuildMediaOptionsSheetFingerprint
import app.revanced.patches.twitter.interaction.downloads.fingerprints.ConstructMediaOptionsSheetFingerprint
import app.revanced.patches.twitter.interaction.downloads.fingerprints.ShowDownloadVideoUpsellBottomSheetFingerprint
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch(
name = "Unlock downloads",
description = "Unlocks the ability to download any video. GIFs can be downloaded via the menu on long press.",
compatiblePackages = [CompatiblePackage("com.twitter.android")],
)
@Suppress("unused")
object UnlockDownloadsPatch : BytecodePatch(
setOf(
ConstructMediaOptionsSheetFingerprint,
ShowDownloadVideoUpsellBottomSheetFingerprint,
BuildMediaOptionsSheetFingerprint,
),
) {
override fun execute(context: BytecodeContext) {
fun MethodFingerprint.patch(getRegisterAndIndex: MethodFingerprintResult.() -> Pair<Int, Int>) = result?.let {
getRegisterAndIndex(it).let { (index, register) ->
it.mutableMethod.addInstruction(index, "const/4 v$register, 0x1")
}
} ?: throw exception
// Allow downloads for non-premium users.
ShowDownloadVideoUpsellBottomSheetFingerprint.patch {
val checkIndex = scanResult.patternScanResult!!.startIndex
val register = mutableMethod.getInstruction<OneRegisterInstruction>(checkIndex).registerA
checkIndex to register
}
// Force show the download menu item.
ConstructMediaOptionsSheetFingerprint.patch {
val showDownloadButtonIndex = mutableMethod.getInstructions().lastIndex - 1
val register = mutableMethod.getInstruction<TwoRegisterInstruction>(showDownloadButtonIndex).registerA
showDownloadButtonIndex to register
}
// Make GIFs downloadable.
BuildMediaOptionsSheetFingerprint.result?.let {
val scanResult = it.scanResult.patternScanResult!!
it.mutableMethod.apply {
val checkMediaTypeIndex = scanResult.startIndex
val checkMediaTypeInstruction = getInstruction<TwoRegisterInstruction>(checkMediaTypeIndex)
// Treat GIFs as videos.
addInstructionsWithLabels(
checkMediaTypeIndex + 1,
"""
const/4 v${checkMediaTypeInstruction.registerB}, 0x2 # GIF
if-eq v${checkMediaTypeInstruction.registerA}, v${checkMediaTypeInstruction.registerB}, :video
""",
ExternalLabel("video", getInstruction(scanResult.endIndex)),
)
// Remove media.isDownloadable check.
removeInstruction(
getInstructions().first { insn -> insn.opcode == Opcode.IGET_BOOLEAN }.location.index + 1,
)
}
} ?: throw BuildMediaOptionsSheetFingerprint.exception
}
}

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.twitter.interaction.downloads.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object BuildMediaOptionsSheetFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.IF_EQ,
Opcode.SGET_OBJECT,
Opcode.GOTO_16,
Opcode.NEW_INSTANCE,
),
strings = listOf("resources.getString(R.string.post_video)"),
)

View File

@@ -0,0 +1,12 @@
package app.revanced.patches.twitter.interaction.downloads.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object ConstructMediaOptionsSheetFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
strings = listOf("captionsState")
)

View File

@@ -0,0 +1,10 @@
package app.revanced.patches.twitter.interaction.downloads.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object ShowDownloadVideoUpsellBottomSheetFingerprint : MethodFingerprint(
returnType = "Z",
strings = listOf("variantToDownload.url"),
opcodes = listOf(Opcode.IF_EQZ)
)

View File

@@ -0,0 +1,30 @@
package app.revanced.patches.twitter.layout.viewcount
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.twitter.layout.viewcount.fingerprints.ViewCountsEnabledFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide view count",
description = "Hides the view count of Posts.",
compatiblePackages = [CompatiblePackage("com.twitter.android")],
use = false
)
@Suppress("unused")
object HideViewCountPatch : BytecodePatch(
setOf(ViewCountsEnabledFingerprint)
) {
override fun execute(context: BytecodeContext) =
ViewCountsEnabledFingerprint.result?.mutableMethod?.addInstructions(
0,
"""
const/4 v0, 0x0
return v0
"""
) ?: throw ViewCountsEnabledFingerprint.exception
}

View File

@@ -0,0 +1,8 @@
package app.revanced.patches.twitter.layout.viewcount.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object ViewCountsEnabledFingerprint : MethodFingerprint(
returnType = "Z",
strings = listOf("view_counts_public_visibility_enabled")
)

View File

@@ -11,12 +11,12 @@ import java.nio.file.Files
@Patch(
name = "Dynamic color",
description = "Replaces the default X (Formerly Twitter) Blue with the user's Material You palette.",
compatiblePackages = [CompatiblePackage("com.twitter.android")]
compatiblePackages = [CompatiblePackage("com.twitter.android")],
)
@Suppress("unused")
object DynamicColorPatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
val resDirectory = context["res"]
val resDirectory = context.get("res")
if (!resDirectory.isDirectory) throw PatchException("The res folder can not be found.")
val valuesV31Directory = resDirectory.resolve("values-v31")
@@ -28,7 +28,7 @@ object DynamicColorPatch : ResourcePatch() {
listOf(valuesV31Directory, valuesNightV31Directory).forEach { it ->
val colorsXml = it.resolve("colors.xml")
if(!colorsXml.exists()) {
if (!colorsXml.exists()) {
FileWriter(colorsXml).use {
it.write("<?xml version=\"1.0\" encoding=\"utf-8\"?><resources></resources>")
}
@@ -46,7 +46,7 @@ object DynamicColorPatch : ResourcePatch() {
"twitter_blue_opacity_30" to "@android:color/system_accent1_100",
"twitter_blue_opacity_50" to "@android:color/system_accent1_200",
"twitter_blue_opacity_58" to "@android:color/system_accent1_300",
"deep_transparent_twitter_blue" to "@android:color/system_accent1_200"
"deep_transparent_twitter_blue" to "@android:color/system_accent1_200",
).forEach { (k, v) ->
val colorElement = document.createElement("color")
@@ -66,7 +66,7 @@ object DynamicColorPatch : ResourcePatch() {
"twitter_blue_opacity_30" to "@android:color/system_accent1_50",
"twitter_blue_opacity_50" to "@android:color/system_accent1_100",
"twitter_blue_opacity_58" to "@android:color/system_accent1_200",
"deep_transparent_twitter_blue" to "@android:color/system_accent1_200"
"deep_transparent_twitter_blue" to "@android:color/system_accent1_200",
).forEach { (k, v) ->
val colorElement = document.createElement("color")

View File

@@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patches.twitter.misc.hook.json.JsonHookPatch
abstract class BaseHookPatch(private val hookClassDescriptor: String) : BytecodePatch() {
abstract class BaseHookPatch(private val hookClassDescriptor: String) : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) =
JsonHookPatch.hooks.addHook(JsonHookPatch.Hook(context, hookClassDescriptor))
}
}

View File

@@ -7,9 +7,8 @@ import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatch
@Patch(
name = "Hide ads",
description = "Hides ads.",
dependencies = [JsonHookPatch::class],
compatiblePackages = [CompatiblePackage("com.twitter.android")]
compatiblePackages = [CompatiblePackage("com.twitter.android")],
)
@Suppress("unused")
object HideAdsHookPatch : BaseHookPatch("Lapp/revanced/integrations/twitter/patches/hook/patch/ads/AdsHook;")
object HideAdsHookPatch : BaseHookPatch("Lapp/revanced/integrations/twitter/patches/hook/patch/ads/AdsHook;")

View File

@@ -0,0 +1,35 @@
package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.twitter.misc.links.fingerprints.OpenLinkFingerprint
import app.revanced.util.exception
@Patch(
name = "Open links with app chooser",
description = "Instead of opening links directly, open them with an app chooser. " +
"As a result you can select a browser to open the link with.",
compatiblePackages = [CompatiblePackage("com.twitter.android")],
use = false,
)
@Suppress("unused")
object OpenLinksWithAppChooserPatch : BytecodePatch(
setOf(OpenLinkFingerprint),
) {
private const val METHOD_REFERENCE =
"Lapp/revanced/integrations/twitter/patches/links/OpenLinksWithAppChooserPatch;->" +
"openWithChooser(Landroid/content/Context;Landroid/content/Intent;)V"
override fun execute(context: BytecodeContext) {
OpenLinkFingerprint.result?.mutableMethod?.addInstructions(
0,
"""
invoke-static { p0, p1 }, $METHOD_REFERENCE
return-void
""",
) ?: throw OpenLinkFingerprint.exception
}
}

View File

@@ -0,0 +1,8 @@
package app.revanced.patches.twitter.misc.links.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object OpenLinkFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf("Landroid/content/Context;", "Landroid/content/Intent;", "Landroid/os/Bundle;"),
)

View File

@@ -1,20 +1,20 @@
package app.revanced.patches.vsco.misc.pro
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.vsco.misc.pro.fingerprints.RevCatSubscriptionFingerprint
import app.revanced.util.exception
@Patch(
name = "Unlock pro",
description = "Unlocks pro features.",
compatiblePackages = [CompatiblePackage("com.vsco.cam")]
compatiblePackages = [CompatiblePackage("com.vsco.cam", ["345"])],
)
object UnlockProPatch : BytecodePatch(
setOf(RevCatSubscriptionFingerprint)
setOf(RevCatSubscriptionFingerprint),
) {
override fun execute(context: BytecodeContext) {
RevCatSubscriptionFingerprint.result?.mutableMethod?.apply {
@@ -23,7 +23,7 @@ object UnlockProPatch : BytecodePatch(
0,
"""
const p1, 0x1
"""
""",
)
} ?: throw RevCatSubscriptionFingerprint.exception
}

View File

@@ -1,7 +1,5 @@
package app.revanced.patches.youtube.ad.general
import app.revanced.util.findMutableMethodOf
import app.revanced.util.injectHideViewCall
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
@@ -9,6 +7,8 @@ import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.misc.fix.verticalscroll.VerticalScrollPatch
import app.revanced.patches.youtube.ad.getpremium.HideGetPremiumPatch
import app.revanced.patches.youtube.misc.fix.backtoexitgesture.FixBackToExitGesturePatch
import app.revanced.util.findMutableMethodOf
import app.revanced.util.injectHideViewCall
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
@@ -20,11 +20,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
HideGetPremiumPatch::class,
HideAdsResourcePatch::class,
VerticalScrollPatch::class,
FixBackToExitGesturePatch::class
FixBackToExitGesturePatch::class,
],
compatiblePackages = [
CompatiblePackage(
"com.google.android.youtube", [
"com.google.android.youtube",
[
"18.32.39",
"18.37.36",
"18.38.44",
@@ -35,30 +36,35 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
]
)
]
"19.03.35",
"19.03.36",
"19.04.37",
],
),
],
)
@Suppress("unused")
object HideAdsPatch : BytecodePatch() {
object HideAdsPatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
if (instruction.opcode != Opcode.CONST)
if (instruction.opcode != Opcode.CONST) {
return@forEachIndexed
}
// Instruction to store the id adAttribution into a register
if ((instruction as Instruction31i).wideLiteral != HideAdsResourcePatch.adAttributionId)
if ((instruction as Instruction31i).wideLiteral != HideAdsResourcePatch.adAttributionId) {
return@forEachIndexed
}
val insertIndex = index + 1
// Call to get the view with the id adAttribution
with(instructions.elementAt(insertIndex)) {
if (opcode != Opcode.INVOKE_VIRTUAL)
if (opcode != Opcode.INVOKE_VIRTUAL) {
return@forEachIndexed
}
// Hide the view
val viewRegister = (this as Instruction35c).registerC
@@ -69,7 +75,7 @@ object HideAdsPatch : BytecodePatch() {
insertIndex,
viewRegister,
"Lapp/revanced/integrations/youtube/patches/components/AdsFilter;",
"hideAdAttributionView"
"hideAdAttributionView",
)
}
}

View File

@@ -30,7 +30,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -35,7 +35,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -13,26 +13,29 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
dependencies = [
CopyVideoUrlResourcePatch::class,
PlayerControlsBytecodePatch::class,
VideoInformationPatch::class
VideoInformationPatch::class,
],
compatiblePackages = [
CompatiblePackage(
"com.google.android.youtube", [
"com.google.android.youtube",
[
"18.48.39",
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
]
)
]
"19.03.35",
"19.03.36",
"19.04.37",
],
),
],
)
@Suppress("unused")
object CopyVideoUrlBytecodePatch : BytecodePatch() {
object CopyVideoUrlBytecodePatch : BytecodePatch(emptySet()) {
private const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/youtube/videoplayer"
private val BUTTONS_DESCRIPTORS = listOf(
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlButton;",
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;"
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;",
)
override fun execute(context: BytecodeContext) {
@@ -42,4 +45,4 @@ object CopyVideoUrlBytecodePatch : BytecodePatch() {
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$descriptor->changeVisibility(Z)V")
}
}
}
}

View File

@@ -32,7 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -13,22 +13,25 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
dependencies = [
ExternalDownloadsResourcePatch::class,
PlayerControlsBytecodePatch::class,
VideoInformationPatch::class
VideoInformationPatch::class,
],
compatiblePackages = [
CompatiblePackage(
"com.google.android.youtube", [
"com.google.android.youtube",
[
"18.48.39",
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
]
"19.03.35",
"19.03.36",
"19.04.37",
],
),
]
],
)
@Suppress("unused")
object ExternalDownloadsBytecodePatch : BytecodePatch() {
object ExternalDownloadsBytecodePatch : BytecodePatch(emptySet()) {
private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
override fun execute(context: BytecodeContext) {
@@ -37,13 +40,15 @@ object ExternalDownloadsBytecodePatch : BytecodePatch() {
*/
PlayerControlsBytecodePatch.initializeControl(
"$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V")
"$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V",
)
/*
add code to change the visibility of the control
*/
PlayerControlsBytecodePatch.injectVisibilityCheckCall(
"$BUTTON_DESCRIPTOR->changeVisibility(Z)V")
"$BUTTON_DESCRIPTOR->changeVisibility(Z)V",
)
}
}
}

View File

@@ -32,7 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -34,7 +34,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -30,7 +30,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
],

View File

@@ -36,7 +36,9 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -34,7 +34,9 @@ import app.revanced.util.exception
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
],

View File

@@ -15,9 +15,9 @@ import java.nio.file.Files
name = "Custom branding",
description = "Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.",
compatiblePackages = [
CompatiblePackage("com.google.android.youtube")
CompatiblePackage("com.google.android.youtube"),
],
use = false
use = false,
)
@Suppress("unused")
object CustomBrandingPatch : ResourcePatch() {
@@ -28,7 +28,7 @@ object CustomBrandingPatch : ResourcePatch() {
"adaptiveproduct_youtube_background_color_108",
"adaptiveproduct_youtube_foreground_color_108",
"ic_launcher",
"ic_launcher_round"
"ic_launcher_round",
).map { "$it.png" }.toTypedArray()
private val mipmapDirectories = arrayOf(
@@ -36,7 +36,7 @@ object CustomBrandingPatch : ResourcePatch() {
"xxhdpi",
"xhdpi",
"hdpi",
"mdpi"
"mdpi",
).map { "mipmap-$it" }
private var appName by stringPatchOption(
@@ -49,7 +49,7 @@ object CustomBrandingPatch : ResourcePatch() {
"YouTube" to "YouTube",
),
title = "App name",
description = "The name of the app."
description = "The name of the app.",
)
private var icon by stringPatchOption(
@@ -58,14 +58,16 @@ object CustomBrandingPatch : ResourcePatch() {
values = mapOf("ReVanced Logo" to REVANCED_ICON),
title = "App icon",
description = """
The path to a folder containing the following folders:
The icon to apply to the app.
If a path to a folder is provided, the folder must contain the following folders:
${mipmapDirectories.joinToString("\n") { "- $it" }}
Each of these folders has to have the following files:
Each of these folders must contain the following files:
${iconResourceFileNames.joinToString("\n") { "- $it" }}
""".trimIndentMultiline()
""".trimIndentMultiline(),
)
override fun execute(context: ResourceContext) {
@@ -73,12 +75,13 @@ object CustomBrandingPatch : ResourcePatch() {
// Change the app icon.
mipmapDirectories.map { directory ->
ResourceGroup(
directory, *iconResourceFileNames
directory,
*iconResourceFileNames,
)
}.let { resourceGroups ->
if (icon != REVANCED_ICON) {
val path = File(icon)
val resourceDirectory = context["res"]
val resourceDirectory = context.get("res")
resourceGroups.forEach { group ->
val fromDirectory = path.resolve(group.resourceDirectoryName)
@@ -87,23 +90,25 @@ object CustomBrandingPatch : ResourcePatch() {
group.resources.forEach { iconFileName ->
Files.write(
toDirectory.resolve(iconFileName).toPath(),
fromDirectory.resolve(iconFileName).readBytes()
fromDirectory.resolve(iconFileName).readBytes(),
)
}
}
} else resourceGroups.forEach { context.copyResources("custom-branding", it) }
} else {
resourceGroups.forEach { context.copyResources("custom-branding", it) }
}
}
}
appName?.let { name ->
// Change the app name.
val manifest = context["AndroidManifest.xml"]
val manifest = context.get("AndroidManifest.xml")
manifest.writeText(
manifest.readText()
.replace(
"android:label=\"@string/application_name",
"android:label=\"$name"
)
"android:label=\"$name",
),
)
}
}

View File

@@ -15,62 +15,69 @@ import java.io.File
name = "Change header",
description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.",
compatiblePackages = [
CompatiblePackage("com.google.android.youtube")
CompatiblePackage("com.google.android.youtube"),
],
use = false
use = false,
)
@Suppress("unused")
object ChangeHeaderPatch : ResourcePatch() {
private const val HEADER_NAME = "yt_wordmark_header"
private const val PREMIUM_HEADER_NAME = "yt_premium_wordmark_header"
private const val REVANCED_HEADER_NAME = "ReVanced"
private const val REVANCED_BORDERLESS_HEADER_NAME = "ReVanced (borderless logo)"
private const val HEADER_FILE_NAME = "yt_wordmark_header"
private const val PREMIUM_HEADER_FILE_NAME = "yt_premium_wordmark_header"
private val targetResourceDirectoryNames = arrayOf(
"xxxhdpi",
"xxhdpi",
"xhdpi",
"mdpi",
"hdpi",
).map { dpi ->
"drawable-$dpi"
}
private const val HEADER_OPTION = "header*"
private const val PREMIUM_HEADER_OPTION = "premium*header"
private const val REVANCED_HEADER_OPTION = "revanced*"
private const val REVANCED_BORDERLESS_HEADER_OPTION = "revanced*borderless"
private val targetResourceDirectoryNames = mapOf(
"xxxhdpi" to "512px x 192px",
"xxhdpi" to "387px x 144px",
"xhdpi" to "258px x 96px",
"hdpi" to "194px x 72px",
"mdpi" to "129px x 48px",
).map { (dpi, dim) ->
"drawable-$dpi" to dim
}.toMap()
private val variants = arrayOf("light", "dark")
private val header by stringPatchOption(
key = "header",
default = REVANCED_BORDERLESS_HEADER_NAME,
default = REVANCED_BORDERLESS_HEADER_OPTION,
values = mapOf(
"YouTube" to HEADER_NAME,
"YouTube Premium" to PREMIUM_HEADER_NAME,
"ReVanced" to REVANCED_HEADER_NAME,
"ReVanced (borderless logo)" to REVANCED_BORDERLESS_HEADER_NAME,
"YouTube" to HEADER_OPTION,
"YouTube Premium" to PREMIUM_HEADER_OPTION,
"ReVanced" to REVANCED_HEADER_OPTION,
"ReVanced (borderless logo)" to REVANCED_BORDERLESS_HEADER_OPTION,
),
title = "Header",
description = """
Either a header name or a path to a custom header folder to use in the top bar.
The path to a folder must contain one or more of the following folders matching the DPI of your device:
The header to apply to the app.
If a path to a folder is provided, the folder must contain one or more of the following folders, depending on the DPI of the device:
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
Each of the folders must contain all of the following files:
${variants.joinToString("\n") { variant -> "- ${HEADER_FILE_NAME}_$variant.png" }}
${targetResourceDirectoryNames.joinToString("\n") { "- $it" }}
These folders must contain the following files:
${variants.joinToString("\n") { variant -> "- ${HEADER_NAME}_$variant.png" }}
The image dimensions must be as follows:
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
""".trimIndentMultiline(),
required = true,
)
override fun execute(context: ResourceContext) {
// The directories to copy the header to.
val targetResourceDirectories = targetResourceDirectoryNames.mapNotNull {
context["res"].resolve(it).takeIf(File::exists)
val targetResourceDirectories = targetResourceDirectoryNames.keys.mapNotNull {
context.get("res").resolve(it).takeIf(File::exists)
}
// The files to replace in the target directories.
val targetResourceFiles = targetResourceDirectoryNames.map { directoryName ->
val targetResourceFiles = targetResourceDirectoryNames.keys.map { directoryName ->
ResourceGroup(
directoryName,
*variants.map { variant -> "${HEADER_NAME}_$variant.png" }.toTypedArray()
*variants.map { variant -> "${HEADER_FILE_NAME}_$variant.png" }.toTypedArray(),
)
}
@@ -89,8 +96,8 @@ object ChangeHeaderPatch : ResourcePatch() {
}
// Functions to overwrite the header to the different variants.
val toPremium = { overwriteFromTo(PREMIUM_HEADER_NAME, HEADER_NAME) }
val toHeader = { overwriteFromTo(HEADER_NAME, PREMIUM_HEADER_NAME) }
val toPremium = { overwriteFromTo(PREMIUM_HEADER_FILE_NAME, HEADER_FILE_NAME) }
val toHeader = { overwriteFromTo(HEADER_FILE_NAME, PREMIUM_HEADER_FILE_NAME) }
val toReVanced = {
// Copy the ReVanced header to the resource directories.
targetResourceFiles.forEach { context.copyResources("change-header/revanced", it) }
@@ -106,32 +113,38 @@ object ChangeHeaderPatch : ResourcePatch() {
toHeader()
}
val toCustom = {
var copiedReplacementImages = false
// For all the resource groups in the custom header folder, copy them to the resource directories.
File(header!!).listFiles { file -> file.isDirectory }?.forEach { folder ->
val targetDirectory = context["res"].resolve(folder.name)
// Skip if the target directory (DPI) doesn't exist.
if (!targetDirectory.exists()) return@forEach
val sourceFolders = File(header!!).listFiles { file -> file.isDirectory }
?: throw PatchException("The provided path is not a directory: $header")
folder.listFiles { file -> file.isFile }?.forEach {
val targetResourceFile = targetDirectory.resolve(it.name)
var copiedFiles = false
it.copyTo(targetResourceFile, true)
copiedReplacementImages = true
// For each source folder, copy the files to the target resource directories.
sourceFolders.forEach { dpiSourceFolder ->
val targetDpiFolder = context.get("res").resolve(dpiSourceFolder.name)
if (!targetDpiFolder.exists()) return@forEach
val imgSourceFiles = dpiSourceFolder.listFiles { file -> file.isFile }!!
imgSourceFiles.forEach { imgSourceFile ->
val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name)
imgSourceFile.copyTo(imgTargetFile, true)
copiedFiles = true
}
}
if (!copiedReplacementImages) throw PatchException("Could not find any custom images resources in directory: $header")
if (!copiedFiles) {
throw PatchException("No header files were copied from the provided path: $header.")
}
// Overwrite the premium with the custom header as well.
toHeader()
}
when (header) {
HEADER_NAME -> toHeader
PREMIUM_HEADER_NAME -> toPremium
REVANCED_HEADER_NAME -> toReVanced
REVANCED_BORDERLESS_HEADER_NAME -> toReVancedBorderless
HEADER_OPTION -> toHeader
PREMIUM_HEADER_OPTION -> toPremium
REVANCED_HEADER_OPTION -> toReVanced
REVANCED_BORDERLESS_HEADER_OPTION -> toReVancedBorderless
else -> toCustom
}()
}

View File

@@ -33,7 +33,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -43,7 +43,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -34,7 +34,9 @@ import com.android.tools.smali.dexlib2.Opcode
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -17,13 +17,13 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
dependencies = [
IntegrationsPatch::class,
SettingsPatch::class,
AddResourcesPatch::class
AddResourcesPatch::class,
],
compatiblePackages = [
CompatiblePackage("com.google.android.youtube")
]
CompatiblePackage("com.google.android.youtube"),
],
)
object HideCastButtonPatch : BytecodePatch() {
object HideCastButtonPatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
@@ -38,7 +38,7 @@ object HideCastButtonPatch : BytecodePatch() {
"""
invoke-static {p1}, Lapp/revanced/integrations/youtube/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I
move-result p1
"""
""",
)
} ?: throw PatchException("setVisibility method not found.")
}

View File

@@ -40,7 +40,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -38,7 +38,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -32,7 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -32,7 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -32,7 +32,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -32,7 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -35,7 +35,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -32,7 +32,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -28,7 +28,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -28,7 +28,9 @@ import app.revanced.util.exception
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -46,7 +46,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]
@@ -59,6 +61,9 @@ object HideLayoutComponentsPatch : BytecodePatch(
"Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;"
private const val DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME =
"Lapp/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter;"
private const val CUSTOM_FILTER_CLASS_NAME =
"Lapp/revanced/integrations/youtube/patches/components/CustomFilter;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
@@ -116,6 +121,7 @@ object HideLayoutComponentsPatch : BytecodePatch(
LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
LithoFilterPatch.addFilter(DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME)
LithoFilterPatch.addFilter(CUSTOM_FILTER_CLASS_NAME)
// region Mix playlists

View File

@@ -39,7 +39,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -28,7 +28,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -33,7 +33,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -30,7 +30,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -37,7 +37,9 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -40,7 +40,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

View File

@@ -27,7 +27,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"18.49.37",
"19.01.34",
"19.02.39",
"19.03.35"
"19.03.35",
"19.03.36",
"19.04.37"
]
)
]

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