chore: Merge branch dev
to main
(#2707)
This commit is contained in:
commit
fa27861ce0
3
.editorconfig
Normal file
3
.editorconfig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[*.{kt,kts}]
|
||||||
|
ktlint_code_style = intellij_idea
|
||||||
|
ktlint_standard_no-wildcard-imports = disabled
|
25
.github/workflows/build_pull_request.yml
vendored
Normal file
25
.github/workflows/build_pull_request.yml
vendored
Normal 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
|
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
|
@ -6,10 +6,6 @@ on:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
- dev
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
@ -41,6 +37,13 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm install
|
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
|
- name: Release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
{
|
{
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"path": "build/libs/*.jar"
|
"path": "build/libs/revanced-patches*"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "patches.json"
|
"path": "patches.json"
|
||||||
|
|
99
CHANGELOG.md
99
CHANGELOG.md
|
@ -1,3 +1,102 @@
|
||||||
|
# [4.3.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.12...v4.3.0-dev.13) (2024-03-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube:** Reorganize settings menu ([#2737](https://github.com/ReVanced/revanced-patches/issues/2737)) ([36132df](https://github.com/ReVanced/revanced-patches/commit/36132df4be6a04c08b6f3dd79de1bcea93a80fb8))
|
||||||
|
|
||||||
|
# [4.3.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.11...v4.3.0-dev.12) (2024-03-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **YouTube - Spoof app version:** Add target versions ([#2787](https://github.com/ReVanced/revanced-patches/issues/2787)) ([83a7bd8](https://github.com/ReVanced/revanced-patches/commit/83a7bd8d69e62623fc4d2ba73d9fb49e92751d89))
|
||||||
|
|
||||||
|
# [4.3.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.10...v4.3.0-dev.11) (2024-03-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof signature:** Fix tracking such as history or watch time ([bcd8b48](https://github.com/ReVanced/revanced-patches/commit/bcd8b48e70693dac1bfcc0bf4971d6b526065b59))
|
||||||
|
|
||||||
|
# [4.3.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.9...v4.3.0-dev.10) (2024-02-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof app version:** Remove broken versions ([#2776](https://github.com/ReVanced/revanced-patches/issues/2776)) ([9466d97](https://github.com/ReVanced/revanced-patches/commit/9466d973c6d7a2891e3fa9f283107b64399152ea))
|
||||||
|
|
||||||
|
# [4.3.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.8...v4.3.0-dev.9) (2024-02-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Override certificate pinning:** Always overwrite with a generic network security configuration ([2a842a1](https://github.com/ReVanced/revanced-patches/commit/2a842a1e14e1993eb028ae0bd1a93e227bb929a6))
|
||||||
|
|
||||||
|
# [4.3.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.7...v4.3.0-dev.8) (2024-02-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Remove extra space from patch description ([#2780](https://github.com/ReVanced/revanced-patches/issues/2780)) ([96a3f35](https://github.com/ReVanced/revanced-patches/commit/96a3f359266ff8d16ae9ee3c6ce2f16ce67a3b93))
|
||||||
|
|
||||||
|
# [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)
|
# [4.2.0](https://github.com/ReVanced/revanced-patches/compare/v4.1.0...v4.2.0) (2024-02-08)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,15 +64,15 @@ This document describes how to contribute to ReVanced Patches.
|
||||||
|
|
||||||
## 📖 Resources to help you get started
|
## 📖 Resources to help you get started
|
||||||
|
|
||||||
* The [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs) provides the fundamentals of patches
|
* The [documentation](https://github.com/ReVanced/revanced-patcher/tree/docs/docs) contains the fundamentals
|
||||||
and everything necessary to create your own patch from scratch
|
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
|
* [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
|
* [Issues](https://github.com/ReVanced/revanced-patches/issues) are where we keep track of bugs and feature requests
|
||||||
|
|
||||||
## 🙏 Submitting a feature request
|
## 🙏 Submitting a feature request
|
||||||
|
|
||||||
Features can be requested by opening an issue using the
|
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**
|
> **Note**
|
||||||
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Patches.
|
> 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
|
## 🐞 Submitting a bug report
|
||||||
|
|
||||||
If you encounter a bug while using ReVanced Patches, open an issue using the
|
If you encounter a bug while using ReVanced Patches, open an issue using the
|
||||||
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=Bug+report&projects=&template=bug-report.yml&title=bug%3A+).
|
[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
|
## 🧑⚖️ Guidelines for requesting or contributing patches
|
||||||
|
|
||||||
|
|
18
README.md
18
README.md
|
@ -67,7 +67,7 @@ This repository contains a collection of ReVanced Patches.
|
||||||
|
|
||||||
## ❓ About
|
## ❓ 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.
|
block ads, customize the appearance, and much more.
|
||||||
|
|
||||||
## 💪 Features
|
## 💪 Features
|
||||||
|
@ -78,10 +78,10 @@ Some of the features the patches provide are:
|
||||||
* ⭐ **Customize your app**: Personalize the appearance of apps with various layouts and themes
|
* ⭐ **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
|
* 🪄 **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,
|
* ⚙️ **Miscellaneous and general purpose**: Rename packages, enable debugging, disable screen capture restrictions,
|
||||||
export activities, etc.
|
export activities, etc.
|
||||||
* ✨ **And much more!**
|
* ✨ **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
|
## 🚀 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).
|
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
|
### 🛠️ 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
|
## 📜 Licence
|
||||||
|
|
||||||
ReVanced Patches is licensed under the GPLv3 licence. Please see the [licence file](LICENSE) for more information.
|
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.
|
[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.
|
Any modifications to ReVanced Patches must also be made available under the GPL,
|
||||||
|
along with build & install instructions.
|
|
@ -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 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 static final field INSTANCE Lapp/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch;
|
||||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
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 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 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 static final field INSTANCE Lapp/revanced/patches/photomath/detection/deviceid/SpoofDeviceIdPatch;
|
||||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
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 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 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 static final field INSTANCE Lapp/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch;
|
||||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||||
|
@ -707,10 +723,8 @@ public abstract class app/revanced/patches/shared/misc/settings/preference/BaseP
|
||||||
}
|
}
|
||||||
|
|
||||||
public class app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$BasePreferenceCollection {
|
public class app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$BasePreferenceCollection {
|
||||||
public fun <init> (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;)V
|
public fun <init> (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;)V
|
||||||
public synthetic fun <init> (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public fun <init> (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;)V
|
|
||||||
public synthetic fun <init> (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
|
||||||
public final fun addPreferences ([Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V
|
public final fun addPreferences ([Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V
|
||||||
public final fun getCategories ()Ljava/util/Set;
|
public final fun getCategories ()Ljava/util/Set;
|
||||||
public synthetic fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;
|
public synthetic fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;
|
||||||
|
@ -782,12 +796,22 @@ public class app/revanced/patches/shared/misc/settings/preference/PreferenceCate
|
||||||
}
|
}
|
||||||
|
|
||||||
public class app/revanced/patches/shared/misc/settings/preference/PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreference {
|
public class app/revanced/patches/shared/misc/settings/preference/PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreference {
|
||||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V
|
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;Ljava/lang/String;Ljava/util/Set;)V
|
||||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public final fun getPreferences ()Ljava/util/Set;
|
public final fun getPreferences ()Ljava/util/Set;
|
||||||
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
|
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting : java/lang/Enum {
|
||||||
|
public static final field BY_KEY Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;
|
||||||
|
public static final field BY_TITLE Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;
|
||||||
|
public static final field UNSORTED Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;
|
||||||
|
public static fun getEntries ()Lkotlin/enums/EnumEntries;
|
||||||
|
public final fun getKeySuffix ()Ljava/lang/String;
|
||||||
|
public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;
|
||||||
|
public static fun values ()[Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/settings/preference/SummaryType : java/lang/Enum {
|
public final class app/revanced/patches/shared/misc/settings/preference/SummaryType : java/lang/Enum {
|
||||||
public static final field DEFAULT Lapp/revanced/patches/shared/misc/settings/preference/SummaryType;
|
public static final field DEFAULT Lapp/revanced/patches/shared/misc/settings/preference/SummaryType;
|
||||||
public static final field OFF Lapp/revanced/patches/shared/misc/settings/preference/SummaryType;
|
public static final field OFF Lapp/revanced/patches/shared/misc/settings/preference/SummaryType;
|
||||||
|
@ -1104,6 +1128,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 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 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 static final field INSTANCE Lapp/revanced/patches/vsco/misc/pro/UnlockProPatch;
|
||||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||||
|
@ -1446,7 +1476,6 @@ public final class app/revanced/patches/youtube/layout/tabletminiplayer/TabletMi
|
||||||
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch;
|
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch;
|
||||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||||
public final fun unwrap (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lkotlin/Triple;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch : app/revanced/patcher/patch/BytecodePatch {
|
public final class app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch : app/revanced/patcher/patch/BytecodePatch {
|
||||||
|
@ -1595,9 +1624,14 @@ public final class app/revanced/patches/youtube/misc/settings/SettingsPatch$Pref
|
||||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/settings/SettingsPatch$PreferenceScreen;
|
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/settings/SettingsPatch$PreferenceScreen;
|
||||||
public fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen;)V
|
public fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen;)V
|
||||||
public final fun getADS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
public final fun getADS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
public final fun getINTERACTIONS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
public final fun getALTERNATIVE_THUMBNAILS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
public final fun getLAYOUT ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
public final fun getFEED ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getGENERAL_LAYOUT ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
public final fun getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
public final fun getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getPLAYER ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getSEEKBAR ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getSHORTS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
|
public final fun getSWIPE_CONTROLS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
public final fun getVIDEO ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
public final fun getVIDEO ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import org.gradle.kotlin.dsl.support.listFilesOrdered
|
import org.gradle.kotlin.dsl.support.listFilesOrdered
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.9.22"
|
alias(libs.plugins.kotlin)
|
||||||
alias(libs.plugins.binary.compatibility.validator)
|
alias(libs.plugins.binary.compatibility.validator)
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
|
signing
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "app.revanced"
|
group = "app.revanced"
|
||||||
|
@ -12,7 +13,14 @@ repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
google()
|
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 {
|
dependencies {
|
||||||
|
@ -22,34 +30,32 @@ dependencies {
|
||||||
implementation(libs.guava)
|
implementation(libs.guava)
|
||||||
// Used in JsonGenerator.
|
// Used in JsonGenerator.
|
||||||
implementation(libs.gson)
|
implementation(libs.gson)
|
||||||
|
|
||||||
// A dependency to the Android library unfortunately fails the build, which is why this is required.
|
|
||||||
compileOnly(project("dummy"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain(11)
|
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 {
|
tasks {
|
||||||
register<DefaultTask>("generateBundle") {
|
withType(Jar::class) {
|
||||||
description = "Generate DEX files and add them in the JAR file"
|
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)
|
dependsOn(build)
|
||||||
|
|
||||||
|
@ -57,39 +63,50 @@ tasks {
|
||||||
val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools")
|
val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools")
|
||||||
.listFilesOrdered().last().resolve("d8").absolutePath
|
.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
|
val workingDirectory = layout.buildDirectory.dir("libs").get().asFile
|
||||||
|
|
||||||
exec {
|
exec {
|
||||||
workingDir = workingDirectory
|
workingDir = workingDirectory
|
||||||
commandLine = listOf(d8, artifacts)
|
commandLine = listOf(d8, "--release", patchesJar)
|
||||||
}
|
}
|
||||||
|
|
||||||
exec {
|
exec {
|
||||||
workingDir = workingDirectory
|
workingDir = workingDirectory
|
||||||
commandLine = listOf("zip", "-u", artifacts, "classes.dex")
|
commandLine = listOf("zip", "-u", patchesJar, "classes.dex")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register<JavaExec>("generateMeta") {
|
register<JavaExec>("generatePatchesFiles") {
|
||||||
description = "Generate metadata for this bundle"
|
description = "Generate patches files"
|
||||||
|
|
||||||
dependsOn(build)
|
dependsOn(build)
|
||||||
|
|
||||||
classpath = sourceSets["main"].runtimeClasspath
|
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
|
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
||||||
named("publish") {
|
publish {
|
||||||
dependsOn("generateBundle")
|
dependsOn("buildDexJar")
|
||||||
dependsOn("generateMeta")
|
dependsOn("generatePatchesFiles")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
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 {
|
publications {
|
||||||
create<MavenPublication>("revanced-patches-publication") {
|
create<MavenPublication>("revanced-patches-publication") {
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
|
@ -121,3 +138,9 @@ publishing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
useGpgCmd()
|
||||||
|
|
||||||
|
sign(publishing.publications["revanced-patches-publication"])
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
plugins {
|
|
||||||
id("java")
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
toolchain {
|
|
||||||
languageVersion.set(JavaLanguageVersion.of(11))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package android.os;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public final class Environment {
|
|
||||||
public static File getExternalStorageDirectory() {
|
|
||||||
throw new UnsupportedOperationException("Stub");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 4.2.0
|
version = 4.3.0-dev.13
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[versions]
|
[versions]
|
||||||
revanced-patcher = "19.2.0"
|
revanced-patcher = "19.3.1"
|
||||||
smali = "3.0.3"
|
smali = "3.0.4"
|
||||||
guava = "33.0.0-jre"
|
guava = "33.0.0-jre"
|
||||||
gson = "2.10.1"
|
gson = "2.10.1"
|
||||||
binary-compatibility-validator = "0.13.2"
|
binary-compatibility-validator = "0.14.0"
|
||||||
|
kotlin = "1.9.22"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
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]
|
[plugins]
|
||||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||||
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
|
|
8
gradle/wrapper/gradle-wrapper.properties
vendored
8
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,8 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dist
|
280
package-lock.json
generated
280
package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.9.1",
|
"gradle-semantic-release-plugin": "^1.9.1",
|
||||||
"semantic-release": "^23.0.0"
|
"semantic-release": "^23.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
|
@ -326,9 +326,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@octokit/request": {
|
"node_modules/@octokit/request": {
|
||||||
"version": "8.1.6",
|
"version": "8.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.2.0.tgz",
|
||||||
"integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==",
|
"integrity": "sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/endpoint": "^9.0.0",
|
"@octokit/endpoint": "^9.0.0",
|
||||||
|
@ -564,6 +564,26 @@
|
||||||
"node": ">= 16"
|
"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": {
|
"node_modules/@saithodev/semantic-release-backmerge/node_modules/mimic-fn": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
||||||
|
@ -1195,9 +1215,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sindresorhus/merge-streams": {
|
"node_modules/@sindresorhus/merge-streams": {
|
||||||
"version": "1.0.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.2.0.tgz",
|
||||||
"integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==",
|
"integrity": "sha512-UTce8mUwUW0RikMb/eseJ7ys0BRkZVFB86orHzrfW12ZmFtym5zua8joZ4L7okH2dDFHkcFjqnZ5GocWBXOFtA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
@ -1282,6 +1302,12 @@
|
||||||
"integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
|
"integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/argparse": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
|
@ -1376,6 +1402,81 @@
|
||||||
"node": ">=6"
|
"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": {
|
"node_modules/cli-table3": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
|
||||||
|
@ -1818,9 +1919,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/escalade": {
|
"node_modules/escalade": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
|
||||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
|
@ -1888,9 +1989,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.16.0",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
|
||||||
"integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==",
|
"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"reusify": "^1.0.4"
|
"reusify": "^1.0.4"
|
||||||
|
@ -2052,12 +2153,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globby": {
|
"node_modules/globby": {
|
||||||
"version": "14.0.0",
|
"version": "14.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz",
|
||||||
"integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==",
|
"integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sindresorhus/merge-streams": "^1.0.0",
|
"@sindresorhus/merge-streams": "^2.1.0",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"ignore": "^5.2.4",
|
"ignore": "^5.2.4",
|
||||||
"path-type": "^5.0.0",
|
"path-type": "^5.0.0",
|
||||||
|
@ -2142,9 +2243,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
|
||||||
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
|
"integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
|
@ -2153,6 +2254,15 @@
|
||||||
"node": ">= 0.4"
|
"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": {
|
"node_modules/hook-std": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz",
|
||||||
|
@ -2178,9 +2288,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/http-proxy-agent": {
|
"node_modules/http-proxy-agent": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.1.tgz",
|
||||||
"integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==",
|
"integrity": "sha512-My1KCEPs6A0hb4qCVzYp8iEvA8j8YqcvXLZZH8C9OFuTYpYjHE7N2dtG3mRl1HMD4+VGXpF3XcDVcxGBT7yDZQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agent-base": "^7.1.0",
|
"agent-base": "^7.1.0",
|
||||||
|
@ -2191,9 +2301,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/https-proxy-agent": {
|
"node_modules/https-proxy-agent": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.3.tgz",
|
||||||
"integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==",
|
"integrity": "sha512-kCnwztfX0KZJSLOBrcL0emLeFako55NWMovvyPP2AjsghNk9RB1yjSI+jVumPHYZsNXegNoqupSW9IY3afSH8w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agent-base": "^7.0.2",
|
"agent-base": "^7.0.2",
|
||||||
|
@ -2213,9 +2323,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||||
"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
|
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
|
@ -2629,9 +2739,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/marked": {
|
"node_modules/marked": {
|
||||||
"version": "11.1.1",
|
"version": "12.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-11.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/marked/-/marked-12.0.0.tgz",
|
||||||
"integrity": "sha512-EgxRjgK9axsQuUa/oKMx5DEY8oXpKJfk61rT5iY3aRlgU6QJtUcxU5OAymdhCvWvhYcd9FKmO5eQoX8m9VGJXg==",
|
"integrity": "sha512-Vkwtq9rLqXryZnWaQc86+FHLC6tr/fycMfYAhiOIXkrNmeGAyhSxjqu0Rs1i0bBqw5u0S7+lV9fdH2ZSVaoa0w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"marked": "bin/marked.js"
|
"marked": "bin/marked.js"
|
||||||
|
@ -2641,14 +2751,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/marked-terminal": {
|
"node_modules/marked-terminal": {
|
||||||
"version": "6.2.0",
|
"version": "7.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.0.0.tgz",
|
||||||
"integrity": "sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==",
|
"integrity": "sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-escapes": "^6.2.0",
|
"ansi-escapes": "^6.2.0",
|
||||||
"cardinal": "^2.1.1",
|
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
|
"cli-highlight": "^2.1.11",
|
||||||
"cli-table3": "^0.6.3",
|
"cli-table3": "^0.6.3",
|
||||||
"node-emoji": "^2.1.3",
|
"node-emoji": "^2.1.3",
|
||||||
"supports-hyperlinks": "^3.0.0"
|
"supports-hyperlinks": "^3.0.0"
|
||||||
|
@ -2657,7 +2767,7 @@
|
||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"marked": ">=1 <12"
|
"marked": ">=1 <13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/meow": {
|
"node_modules/meow": {
|
||||||
|
@ -2739,6 +2849,17 @@
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/neo-async": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||||
|
@ -5551,6 +5672,15 @@
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC"
|
"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": {
|
"node_modules/once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
|
@ -5695,6 +5825,27 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/parsimmon": {
|
||||||
"version": "1.18.1",
|
"version": "1.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz",
|
||||||
|
@ -5860,9 +6011,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/read-pkg-up/node_modules/type-fest": {
|
"node_modules/read-pkg-up/node_modules/type-fest": {
|
||||||
"version": "4.10.1",
|
"version": "4.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz",
|
||||||
"integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==",
|
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
|
@ -5889,9 +6040,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/read-pkg/node_modules/type-fest": {
|
"node_modules/read-pkg/node_modules/type-fest": {
|
||||||
"version": "4.10.1",
|
"version": "4.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz",
|
||||||
"integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==",
|
"integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
|
@ -5994,9 +6145,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/semantic-release": {
|
"node_modules/semantic-release": {
|
||||||
"version": "23.0.0",
|
"version": "23.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.2.tgz",
|
||||||
"integrity": "sha512-Jz7jEWO2igTtske112gC4PPE2whCMVrsgxUPG3/SZI7VE357suIUZFlJd1Yu0g2I6RPc2HxNEfUg7KhmDTjwqg==",
|
"integrity": "sha512-OnVYJ6Xgzwe1x8MKswba7RU9+5djS1MWRTrTn5qsq3xZYpslroZkV9Pt0dA2YcIuieeuSZWJhn+yUWoBUHO5Fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@semantic-release/commit-analyzer": "^11.0.0",
|
"@semantic-release/commit-analyzer": "^11.0.0",
|
||||||
|
@ -6017,8 +6168,8 @@
|
||||||
"hosted-git-info": "^7.0.0",
|
"hosted-git-info": "^7.0.0",
|
||||||
"import-from-esm": "^1.3.1",
|
"import-from-esm": "^1.3.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"marked": "^11.0.0",
|
"marked": "^12.0.0",
|
||||||
"marked-terminal": "^6.0.0",
|
"marked-terminal": "^7.0.0",
|
||||||
"micromatch": "^4.0.2",
|
"micromatch": "^4.0.2",
|
||||||
"p-each-series": "^3.0.0",
|
"p-each-series": "^3.0.0",
|
||||||
"p-reduce": "^3.0.0",
|
"p-reduce": "^3.0.0",
|
||||||
|
@ -6247,9 +6398,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.5.4",
|
"version": "7.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": "^6.0.0"
|
"lru-cache": "^6.0.0"
|
||||||
|
@ -6481,9 +6632,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/spdx-license-ids": {
|
"node_modules/spdx-license-ids": {
|
||||||
"version": "3.0.16",
|
"version": "3.0.17",
|
||||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz",
|
||||||
"integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==",
|
"integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/split2": {
|
"node_modules/split2": {
|
||||||
|
@ -6655,6 +6806,27 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.9.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
|
@ -1,5 +1,3 @@
|
||||||
include("dummy")
|
|
||||||
|
|
||||||
rootProject.name = "revanced-patches"
|
rootProject.name = "revanced-patches"
|
||||||
|
|
||||||
buildCache {
|
buildCache {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package app.revanced.meta
|
package app.revanced.generator
|
||||||
|
|
||||||
import app.revanced.patcher.PatchSet
|
import app.revanced.patcher.PatchSet
|
||||||
import app.revanced.patcher.patch.Patch
|
import app.revanced.patcher.patch.Patch
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
|
internal class JsonPatchesFileGenerator : PatchesFileGenerator {
|
||||||
override fun generate(patches: PatchSet) = patches.map {
|
override fun generate(patches: PatchSet) = patches.map {
|
||||||
JsonPatch(
|
JsonPatch(
|
||||||
it.name!!,
|
it.name!!,
|
||||||
|
@ -20,9 +20,9 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
|
||||||
option.values,
|
option.values,
|
||||||
option.title,
|
option.title,
|
||||||
option.description,
|
option.description,
|
||||||
option.required
|
option.required,
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}.let {
|
}.let {
|
||||||
File("patches.json").writeText(GsonBuilder().serializeNulls().create().toJson(it))
|
File("patches.json").writeText(GsonBuilder().serializeNulls().create().toJson(it))
|
||||||
|
@ -35,7 +35,7 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator {
|
||||||
val compatiblePackages: Set<Patch.CompatiblePackage>? = null,
|
val compatiblePackages: Set<Patch.CompatiblePackage>? = null,
|
||||||
val use: Boolean = true,
|
val use: Boolean = true,
|
||||||
val requiresIntegrations: Boolean = false,
|
val requiresIntegrations: Boolean = false,
|
||||||
val options: List<Option>
|
val options: List<Option>,
|
||||||
) {
|
) {
|
||||||
class Option(
|
class Option(
|
||||||
val key: String,
|
val key: String,
|
12
src/main/kotlin/app/revanced/generator/Main.kt
Normal file
12
src/main/kotlin/app/revanced/generator/Main.kt
Normal 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) }
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package app.revanced.generator
|
||||||
|
|
||||||
|
import app.revanced.patcher.PatchSet
|
||||||
|
|
||||||
|
internal interface PatchesFileGenerator {
|
||||||
|
fun generate(patches: PatchSet)
|
||||||
|
}
|
|
@ -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) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,29 +7,34 @@ import app.revanced.patcher.patch.annotation.Patch
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Export all activities",
|
name = "Export all activities",
|
||||||
description = "Makes all app activities exportable.",
|
description = "Makes all app activities exportable.",
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object ExportAllActivitiesPatch : ResourcePatch() {
|
object ExportAllActivitiesPatch : ResourcePatch() {
|
||||||
private const val EXPORTED_FLAG = "android:exported"
|
private const val EXPORTED_FLAG = "android:exported"
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val document = editor.file
|
val document = editor.file
|
||||||
|
|
||||||
val activities = document.getElementsByTagName("activity")
|
val activities = document.getElementsByTagName("activity")
|
||||||
|
|
||||||
for(i in 0..activities.length) {
|
for (i in 0..activities.length) {
|
||||||
activities.item(i)?.apply {
|
activities.item(i)?.apply {
|
||||||
val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG)
|
val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG)
|
||||||
|
|
||||||
if (exportedAttribute != null) {
|
if (exportedAttribute != null) {
|
||||||
if (exportedAttribute.nodeValue != "true")
|
if (exportedAttribute.nodeValue != "true") {
|
||||||
exportedAttribute.nodeValue = "true"
|
exportedAttribute.nodeValue = "true"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Reason why the attribute is added in the case it does not exist:
|
// Reason why the attribute is added in the case it does not exist:
|
||||||
// https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604
|
// https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604
|
||||||
else document.createAttribute(EXPORTED_FLAG)
|
else {
|
||||||
.apply { value = "true" }
|
document.createAttribute(EXPORTED_FLAG)
|
||||||
.let(attributes::setNamedItem)
|
.apply { value = "true" }
|
||||||
|
.let(attributes::setNamedItem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import app.revanced.patcher.patch.annotation.Patch
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Predictive back gesture",
|
name = "Predictive back gesture",
|
||||||
description = "Enables the predictive back gesture introduced on Android 13.",
|
description = "Enables the predictive back gesture introduced on Android 13.",
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object PredictiveBackGesturePatch : ResourcePatch() {
|
object PredictiveBackGesturePatch : ResourcePatch() {
|
||||||
|
|
|
@ -8,16 +8,18 @@ import org.w3c.dom.Element
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Enable Android debugging",
|
name = "Enable Android debugging",
|
||||||
description = "Enables Android debugging capabilities. This can slow down the app.",
|
description = "Enables Android debugging capabilities. This can slow down the app.",
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object EnableAndroidDebuggingPatch : ResourcePatch() {
|
object EnableAndroidDebuggingPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { dom ->
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val applicationNode = dom
|
val document = editor.file
|
||||||
.file
|
|
||||||
.getElementsByTagName("application")
|
val applicationNode =
|
||||||
.item(0) as Element
|
document
|
||||||
|
.getElementsByTagName("application")
|
||||||
|
.item(0) as Element
|
||||||
|
|
||||||
// set application as debuggable
|
// set application as debuggable
|
||||||
applicationNode.setAttribute("android:debuggable", "true")
|
applicationNode.setAttribute("android:debuggable", "true")
|
||||||
|
|
|
@ -4,6 +4,7 @@ import app.revanced.patcher.data.ResourceContext
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.all.misc.debugging.EnableAndroidDebuggingPatch
|
import app.revanced.patches.all.misc.debugging.EnableAndroidDebuggingPatch
|
||||||
|
import app.revanced.util.Utils.trimIndentMultiline
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
@ -11,16 +12,17 @@ import java.io.File
|
||||||
name = "Override certificate pinning",
|
name = "Override certificate pinning",
|
||||||
description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.",
|
description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.",
|
||||||
dependencies = [EnableAndroidDebuggingPatch::class],
|
dependencies = [EnableAndroidDebuggingPatch::class],
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object OverrideCertificatePinningPatch : ResourcePatch() {
|
object OverrideCertificatePinningPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
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.
|
// Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist.
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val document = editor.file
|
val document = editor.file
|
||||||
|
|
||||||
val applicationNode = document.getElementsByTagName("application").item(0) as Element
|
val applicationNode = document.getElementsByTagName("application").item(0) as Element
|
||||||
|
|
||||||
if (!applicationNode.hasAttribute("networkSecurityConfig")) {
|
if (!applicationNode.hasAttribute("networkSecurityConfig")) {
|
||||||
|
@ -31,10 +33,8 @@ object OverrideCertificatePinningPatch : ResourcePatch() {
|
||||||
|
|
||||||
// In case the file does not exist create the "network_security_config.xml" file.
|
// In case the file does not exist create the "network_security_config.xml" file.
|
||||||
File(resXmlDirectory, "network_security_config.xml").apply {
|
File(resXmlDirectory, "network_security_config.xml").apply {
|
||||||
if (!exists()) {
|
writeText(
|
||||||
createNewFile()
|
"""
|
||||||
writeText(
|
|
||||||
"""
|
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<network-security-config>
|
<network-security-config>
|
||||||
<base-config cleartextTrafficPermitted="true">
|
<base-config cleartextTrafficPermitted="true">
|
||||||
|
@ -54,22 +54,8 @@ object OverrideCertificatePinningPatch : ResourcePatch() {
|
||||||
</trust-anchors>
|
</trust-anchors>
|
||||||
</debug-overrides>
|
</debug-overrides>
|
||||||
</network-security-config>
|
</network-security-config>
|
||||||
"""
|
""".trimIndentMultiline(),
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
// If the file already exists.
|
|
||||||
readText().let { text ->
|
|
||||||
if (!text.contains("<certificates src=\"user\" />")) {
|
|
||||||
writeText(
|
|
||||||
text.replace(
|
|
||||||
"<trust-anchors>",
|
|
||||||
"<trust-anchors>\n<certificates src=\"user\" overridePins=\"true\" />\n<certificates src=\"system\" />"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,21 @@ import java.io.Closeable
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Change package name",
|
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.",
|
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")
|
@Suppress("unused")
|
||||||
object ChangePackageNamePatch : ResourcePatch(), Closeable {
|
object ChangePackageNamePatch : ResourcePatch(), Closeable {
|
||||||
private val packageNameOption = stringPatchOption(
|
private val packageNameOption =
|
||||||
key = "packageName",
|
stringPatchOption(
|
||||||
default = "Default",
|
key = "packageName",
|
||||||
values = mapOf("Default" to "Default"),
|
default = "Default",
|
||||||
title = "Package name",
|
values = mapOf("Default" to "Default"),
|
||||||
description = "The name of the package to rename the app to.",
|
title = "Package name",
|
||||||
required = true
|
description = "The name of the package to rename the app to.",
|
||||||
) {
|
required = true,
|
||||||
it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$"))
|
) {
|
||||||
}
|
it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$"))
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var context: ResourceContext
|
private lateinit var context: ResourceContext
|
||||||
|
|
||||||
|
@ -43,20 +44,27 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable {
|
||||||
fun setOrGetFallbackPackageName(fallbackPackageName: String): String {
|
fun setOrGetFallbackPackageName(fallbackPackageName: String): String {
|
||||||
val packageName = packageNameOption.value!!
|
val packageName = packageNameOption.value!!
|
||||||
|
|
||||||
return if (packageName == packageNameOption.default)
|
return if (packageName == packageNameOption.default) {
|
||||||
fallbackPackageName.also { packageNameOption.value = it }
|
fallbackPackageName.also { packageNameOption.value = it }
|
||||||
else
|
} else {
|
||||||
packageName
|
packageName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() = context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
override fun close() =
|
||||||
val replacementPackageName = packageNameOption.value
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
|
val document = editor.file
|
||||||
|
|
||||||
val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
|
val replacementPackageName = packageNameOption.value
|
||||||
manifest.setAttribute(
|
|
||||||
"package",
|
val manifest = document.getElementsByTagName("manifest").item(0) as Element
|
||||||
if (replacementPackageName != packageNameOption.default) replacementPackageName
|
manifest.setAttribute(
|
||||||
else "${manifest.getAttribute("package")}.revanced"
|
"package",
|
||||||
)
|
if (replacementPackageName != packageNameOption.default) {
|
||||||
}
|
replacementPackageName
|
||||||
|
} else {
|
||||||
|
"${manifest.getAttribute("package")}.revanced"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.*
|
||||||
* An identifier of an app. For example, `youtube`.
|
* An identifier of an app. For example, `youtube`.
|
||||||
*/
|
*/
|
||||||
private typealias AppId = String
|
private typealias AppId = String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An identifier of a patch. For example, `ad.general.HideAdsPatch`.
|
* 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.
|
* A set of resources of a patch.
|
||||||
*/
|
*/
|
||||||
private typealias PatchResources = MutableSet<BaseResource>
|
private typealias PatchResources = MutableSet<BaseResource>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of resources belonging to a patch.
|
* A map of resources belonging to a patch.
|
||||||
*/
|
*/
|
||||||
private typealias AppResources = MutableMap<PatchId, PatchResources>
|
private typealias AppResources = MutableMap<PatchId, PatchResources>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of resources belonging to an app.
|
* A map of resources belonging to an app.
|
||||||
*/
|
*/
|
||||||
|
@ -67,40 +70,44 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
this.context = context
|
this.context = context
|
||||||
|
|
||||||
resources = buildMap {
|
resources =
|
||||||
/**
|
buildMap {
|
||||||
* Puts resources under `/resources/addresources/<value>/<resourceKind>.xml` into the map.
|
/**
|
||||||
*
|
* 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 value The value of the resource. For example, `values` or `values-de`.
|
||||||
* @param transform A function that transforms the [Node]s from the XML files to a [BaseResource].
|
* @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,
|
fun addResources(
|
||||||
resourceKind: String,
|
value: Value,
|
||||||
transform: (Node) -> BaseResource,
|
resourceKind: String,
|
||||||
) {
|
transform: (Node) -> BaseResource,
|
||||||
inputStreamFromBundledResource(
|
) {
|
||||||
"addresources",
|
inputStreamFromBundledResource(
|
||||||
"$value/$resourceKind.xml"
|
"addresources",
|
||||||
)?.let { stream ->
|
"$value/$resourceKind.xml",
|
||||||
// Add the resources associated with the given value to the map,
|
)?.let { stream ->
|
||||||
// instead of overwriting it.
|
// Add the resources associated with the given value to the map,
|
||||||
// This covers the example case such as adding strings and arrays of the same value.
|
// instead of overwriting it.
|
||||||
getOrPut(value, ::mutableMapOf).apply {
|
// This covers the example case such as adding strings and arrays of the same value.
|
||||||
context.xmlEditor[stream].use {
|
getOrPut(value, ::mutableMapOf).apply {
|
||||||
it.file.getElementsByTagName("app").asSequence().forEach { app ->
|
context.xmlEditor[stream].use { editor ->
|
||||||
val appId = app.attributes.getNamedItem("id").textContent
|
val document = editor.file
|
||||||
|
|
||||||
getOrPut(appId, ::mutableMapOf).apply {
|
document.getElementsByTagName("app").asSequence().forEach { app ->
|
||||||
app.forEachChildElement { patch ->
|
val appId = app.attributes.getNamedItem("id").textContent
|
||||||
val patchId = patch.attributes.getNamedItem("id").textContent
|
|
||||||
|
|
||||||
getOrPut(patchId, ::mutableSetOf).apply {
|
getOrPut(appId, ::mutableMapOf).apply {
|
||||||
patch.forEachChildElement { resourceNode ->
|
app.forEachChildElement { patch ->
|
||||||
val resource = transform(resourceNode)
|
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.
|
// Stage all resources to a temporary map.
|
||||||
// Staged resources consumed by AddResourcesPatch#invoke(PatchClass)
|
// Staged resources consumed by AddResourcesPatch#invoke(PatchClass)
|
||||||
// are later used in AddResourcesPatch#close.
|
// are later used in AddResourcesPatch#close.
|
||||||
try {
|
try {
|
||||||
val addStringResources = { value: Value ->
|
val addStringResources = { value: Value ->
|
||||||
addResources(value, "strings", StringResource::fromNode)
|
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.
|
* @return True if the resource was added, false if it already existed.
|
||||||
*/
|
*/
|
||||||
operator fun invoke(value: Value, resource: BaseResource) =
|
operator fun invoke(
|
||||||
getOrPut(value, ::mutableSetOf).add(resource)
|
value: Value,
|
||||||
|
resource: BaseResource,
|
||||||
|
) = getOrPut(value, ::mutableSetOf).add(resource)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a list of [BaseResource]s to the map using [MutableMap.getOrPut].
|
* 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.
|
* @return True if the resources were added, false if they already existed.
|
||||||
*/
|
*/
|
||||||
operator fun invoke(value: Value, resources: Iterable<BaseResource>) =
|
operator fun invoke(
|
||||||
getOrPut(value, ::mutableSetOf).addAll(resources)
|
value: Value,
|
||||||
|
resources: Iterable<BaseResource>,
|
||||||
|
) = getOrPut(value, ::mutableSetOf).addAll(resources)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a [StringResource].
|
* Adds a [StringResource].
|
||||||
|
@ -177,10 +187,9 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
|
||||||
*/
|
*/
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
name: String,
|
name: String,
|
||||||
items: List<String>
|
items: List<String>,
|
||||||
) = invoke("values", ArrayResource(name, items))
|
) = invoke("values", ArrayResource(name, items))
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts all resources of any [Value] staged in [resources] for the given [PatchClass] to [AddResourcesPatch].
|
* 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
|
appId to patchId
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val (appId, patchId) = patch.parseIds()
|
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.
|
// Stage resources for the given patch to AddResourcesPatch associated with their value.
|
||||||
resources.forEach { (value, resources) ->
|
resources.forEach { (value, resources) ->
|
||||||
resources[appId]?.get(patchId)?.let { patchResources ->
|
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() {
|
override fun close() {
|
||||||
operator fun MutableMap<String, Pair<DomFileEditor, Node>>.invoke(
|
operator fun MutableMap<String, Pair<DomFileEditor, Node>>.invoke(
|
||||||
value: Value,
|
value: Value,
|
||||||
resource: BaseResource
|
resource: BaseResource,
|
||||||
) {
|
) {
|
||||||
// TODO: Fix open-closed principle violation by modifying BaseResource#serialize so that it accepts
|
// 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.
|
// to serialize itself to it.
|
||||||
val resourceFileName = when (resource) {
|
val resourceFileName =
|
||||||
is StringResource -> "strings"
|
when (resource) {
|
||||||
is ArrayResource -> "arrays"
|
is StringResource -> "strings"
|
||||||
else -> throw NotImplementedError("Unsupported resource type")
|
is ArrayResource -> "arrays"
|
||||||
}
|
else -> throw NotImplementedError("Unsupported resource type")
|
||||||
|
|
||||||
getOrPut(resourceFileName) {
|
|
||||||
val targetFile = context["res/$value/$resourceFileName.xml"].also {
|
|
||||||
it.parentFile?.mkdirs()
|
|
||||||
it.createNewFile()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOrPut(resourceFileName) {
|
||||||
|
val targetFile =
|
||||||
|
context.get("res/$value/$resourceFileName.xml").also {
|
||||||
|
it.parentFile?.mkdirs()
|
||||||
|
it.createNewFile()
|
||||||
|
}
|
||||||
|
|
||||||
context.xmlEditor[targetFile.path].let { editor ->
|
context.xmlEditor[targetFile.path].let { editor ->
|
||||||
|
val document = editor.file
|
||||||
|
|
||||||
// Save the target node here as well
|
// Save the target node here as well
|
||||||
// in order to avoid having to call editor.getNode("resources")
|
// in order to avoid having to call document.getNode("resources")
|
||||||
// every time addUsingEditors is called but also save the editor so that it can be closed later.
|
// but also save the document so that it can be closed later.
|
||||||
editor to editor.getNode("resources")
|
editor to document.getNode("resources")
|
||||||
}
|
}
|
||||||
}.let { (_, targetNode) ->
|
}.let { (_, targetNode) ->
|
||||||
targetNode.addResource(resource) { invoke(value, it) }
|
targetNode.addResource(resource) { invoke(value, it) }
|
||||||
|
@ -261,17 +274,17 @@ object AddResourcesPatch : ResourcePatch(), MutableMap<Value, MutableSet<BaseRes
|
||||||
}
|
}
|
||||||
|
|
||||||
forEach { (value, resources) ->
|
forEach { (value, resources) ->
|
||||||
// A map of editors associated by their kind (e.g. strings, arrays).
|
// A map of document associated by their kind (e.g. strings, arrays).
|
||||||
// Each editor is accompanied by the target node to which resources are added.
|
// Each document 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 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.
|
// 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.
|
// 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.
|
// This map is later accessed to close all documents for the current resource value.
|
||||||
val resourceFileEditors = mutableMapOf<String, Pair<DomFileEditor, Node>>()
|
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() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,12 @@ import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
abstract class BaseTransformInstructionsPatch<T> : BytecodePatch() {
|
abstract class BaseTransformInstructionsPatch<T> : BytecodePatch(emptySet()) {
|
||||||
abstract fun filterMap(
|
abstract fun filterMap(
|
||||||
classDef: ClassDef,
|
classDef: ClassDef,
|
||||||
method: Method,
|
method: Method,
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
instructionIndex: Int
|
instructionIndex: Int,
|
||||||
): T?
|
): T?
|
||||||
|
|
||||||
abstract fun transform(mutableMethod: MutableMethod, entry: T)
|
abstract fun transform(mutableMethod: MutableMethod, entry: T)
|
||||||
|
|
|
@ -8,13 +8,14 @@ import org.w3c.dom.Element
|
||||||
@Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.")
|
@Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.")
|
||||||
internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() {
|
internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
// create an xml editor instance
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { dom ->
|
val document = editor.file
|
||||||
|
|
||||||
// get the application node
|
// get the application node
|
||||||
val applicationNode = dom
|
val applicationNode =
|
||||||
.file
|
document
|
||||||
.getElementsByTagName("application")
|
.getElementsByTagName("application")
|
||||||
.item(0) as Element
|
.item(0) as Element
|
||||||
|
|
||||||
// set allowAudioPlaybackCapture attribute to true
|
// set allowAudioPlaybackCapture attribute to true
|
||||||
applicationNode.setAttribute("android:allowAudioPlaybackCapture", "true")
|
applicationNode.setAttribute("android:allowAudioPlaybackCapture", "true")
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
)
|
|
|
@ -1,14 +1,12 @@
|
||||||
package app.revanced.patches.music.misc.gms.fingerprints
|
package app.revanced.patches.music.misc.gms.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
|
||||||
internal object ServiceCheckFingerprint : MethodFingerprint(
|
internal object ServiceCheckFingerprint : MethodFingerprint(
|
||||||
"V",
|
"V",
|
||||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
listOf("L", "I"),
|
listOf("L", "I"),
|
||||||
strings = listOf("Google Play Services not available")
|
strings = listOf("Google Play Services not available"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,8 +6,5 @@ import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||||
|
|
||||||
@Patch(requiresIntegrations = true)
|
@Patch(requiresIntegrations = true)
|
||||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||||
"Lapp/revanced/integrations/utils/ReVancedUtils;",
|
setOf(ApplicationInitFingerprint),
|
||||||
setOf(
|
|
||||||
ApplicationInitFingerprint,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,23 +6,24 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Remove broadcasts restriction",
|
name = "Remove broadcasts restriction",
|
||||||
description = "Enables starting/stopping NetGuard via broadcasts.",
|
description = "Enables starting/stopping NetGuard via broadcasts.",
|
||||||
compatiblePackages = [CompatiblePackage("eu.faircode.netguard")],
|
compatiblePackages = [CompatiblePackage("eu.faircode.netguard")],
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object RemoveBroadcastsRestrictionPatch : ResourcePatch() {
|
object RemoveBroadcastsRestrictionPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor["AndroidManifest.xml"].use { dom ->
|
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val applicationNode = dom
|
val document = editor.file
|
||||||
.file
|
|
||||||
.getElementsByTagName("application")
|
|
||||||
.item(0) as Element
|
|
||||||
|
|
||||||
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) {
|
for (i in 0 until list.length) {
|
||||||
val element = list.item(i) as? Element ?: continue
|
val element = list.item(i) as? Element ?: continue
|
||||||
if (element.getAttribute("android:name") == "eu.faircode.netguard.WidgetAdmin") {
|
if (element.getAttribute("android:name") == "eu.faircode.netguard.WidgetAdmin") {
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
|
@ -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"
|
||||||
|
},
|
||||||
|
)
|
|
@ -9,8 +9,10 @@ object HideBannerPatch : ResourcePatch() {
|
||||||
private const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml"
|
private const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml"
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.xmlEditor[RESOURCE_FILE_PATH].use {
|
context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
|
||||||
it.file.getElementsByTagName("merge").item(0).childNodes.apply {
|
val document = editor.file
|
||||||
|
|
||||||
|
document.getElementsByTagName("merge").item(0).childNodes.apply {
|
||||||
val attributes = arrayOf("height", "width")
|
val attributes = arrayOf("height", "width")
|
||||||
|
|
||||||
for (i in 1 until length) {
|
for (i in 1 until length) {
|
||||||
|
@ -30,4 +32,3 @@ object HideBannerPatch : ResourcePatch() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.reddit.ad.comments.fingerprints.HideCommentAdsFingerprint
|
import app.revanced.patches.reddit.ad.comments.fingerprints.HideCommentAdsFingerprint
|
||||||
|
|
||||||
@Patch(description = "Removes ads in the comments.",)
|
@Patch(description = "Removes ads in the comments.")
|
||||||
object HideCommentAdsPatch : BytecodePatch(
|
object HideCommentAdsPatch : BytecodePatch(
|
||||||
setOf(HideCommentAdsFingerprint)
|
setOf(HideCommentAdsFingerprint)
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -6,18 +6,13 @@ import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint
|
import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint
|
||||||
|
|
||||||
@Patch(description = "Disables detection of modified versions.",)
|
@Patch(description = "Disables detection of modified versions.")
|
||||||
object DisablePiracyDetectionPatch : BytecodePatch(setOf(PiracyDetectionFingerprint)) {
|
object DisablePiracyDetectionPatch : BytecodePatch(setOf(PiracyDetectionFingerprint)) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
// Do not throw an error if the fingerprint is not resolved.
|
// Do not throw an error if the fingerprint is not resolved.
|
||||||
// This is fine because new versions of the target app do not need this patch.
|
// This is fine because new versions of the target app do not need this patch.
|
||||||
PiracyDetectionFingerprint.result?.mutableMethod?.apply {
|
PiracyDetectionFingerprint.result?.mutableMethod?.apply {
|
||||||
addInstruction(
|
addInstruction(0, "return-void")
|
||||||
0,
|
|
||||||
"""
|
|
||||||
return-void
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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: ")
|
||||||
|
)
|
|
@ -22,19 +22,21 @@ abstract class BaseGmsCoreSupportResourcePatch(
|
||||||
private val fromPackageName: String,
|
private val fromPackageName: String,
|
||||||
private val toPackageName: String,
|
private val toPackageName: String,
|
||||||
private val spoofedPackageSignature: String,
|
private val spoofedPackageSignature: String,
|
||||||
dependencies: Set<PatchClass> = setOf()
|
dependencies: Set<PatchClass> = setOf(),
|
||||||
) : ResourcePatch(dependencies = setOf(ChangePackageNamePatch::class, AddResourcesPatch::class) + dependencies) {
|
) : ResourcePatch(dependencies = setOf(ChangePackageNamePatch::class, AddResourcesPatch::class) + dependencies) {
|
||||||
internal val gmsCoreVendorOption = stringPatchOption(
|
internal val gmsCoreVendorOption =
|
||||||
key = "gmsCoreVendor",
|
stringPatchOption(
|
||||||
default = "com.mgoogle",
|
key = "gmsCoreVendor",
|
||||||
values = mapOf(
|
default = "com.mgoogle",
|
||||||
"Vanced" to "com.mgoogle",
|
values =
|
||||||
"ReVanced" to "app.revanced"
|
mapOf(
|
||||||
),
|
"Vanced" to "com.mgoogle",
|
||||||
title = "GmsCore Vendor",
|
"ReVanced" to "app.revanced",
|
||||||
description = "The group id of the GmsCore vendor.",
|
),
|
||||||
required = true
|
title = "GmsCore Vendor",
|
||||||
) { it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) }
|
description = "The group id of the GmsCore vendor.",
|
||||||
|
required = true,
|
||||||
|
) { it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) }
|
||||||
|
|
||||||
protected val gmsCoreVendor by gmsCoreVendorOption
|
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.
|
* Add metadata to manifest to support spoofing the package name and signature of GmsCore.
|
||||||
*/
|
*/
|
||||||
private fun ResourceContext.addSpoofingMetadata() {
|
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)
|
val child = ownerDocument.createElement(tagName)
|
||||||
child.block()
|
child.block()
|
||||||
appendChild(child)
|
appendChild(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlEditor["AndroidManifest.xml"].use {
|
xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||||
val applicationNode = it
|
val document = editor.file
|
||||||
.file
|
|
||||||
.getElementsByTagName("application")
|
val applicationNode =
|
||||||
.item(0)
|
document
|
||||||
|
.getElementsByTagName("application")
|
||||||
|
.item(0)
|
||||||
|
|
||||||
// Spoof package name and signature.
|
// Spoof package name and signature.
|
||||||
applicationNode.adoptChild("meta-data") {
|
applicationNode.adoptChild("meta-data") {
|
||||||
|
@ -87,27 +94,27 @@ abstract class BaseGmsCoreSupportResourcePatch(
|
||||||
private fun ResourceContext.patchManifest() {
|
private fun ResourceContext.patchManifest() {
|
||||||
val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName)
|
val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName)
|
||||||
|
|
||||||
val manifest = this["AndroidManifest.xml"].readText()
|
val manifest = this.get("AndroidManifest.xml").readText()
|
||||||
this["AndroidManifest.xml"].writeText(
|
this.get("AndroidManifest.xml").writeText(
|
||||||
manifest.replace(
|
manifest.replace(
|
||||||
"package=\"$fromPackageName",
|
"package=\"$fromPackageName",
|
||||||
"package=\"$packageName"
|
"package=\"$packageName",
|
||||||
).replace(
|
).replace(
|
||||||
"android:authorities=\"$fromPackageName",
|
"android:authorities=\"$fromPackageName",
|
||||||
"android:authorities=\"$packageName"
|
"android:authorities=\"$packageName",
|
||||||
).replace(
|
).replace(
|
||||||
"$fromPackageName.permission.C2D_MESSAGE",
|
"$fromPackageName.permission.C2D_MESSAGE",
|
||||||
"$packageName.permission.C2D_MESSAGE"
|
"$packageName.permission.C2D_MESSAGE",
|
||||||
).replace(
|
).replace(
|
||||||
"$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
"$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
||||||
"$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
|
"$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION",
|
||||||
).replace(
|
).replace(
|
||||||
"com.google.android.c2dm",
|
"com.google.android.c2dm",
|
||||||
"$gmsCoreVendor.android.c2dm"
|
"$gmsCoreVendor.android.c2dm",
|
||||||
).replace(
|
).replace(
|
||||||
"</queries>",
|
"</queries>",
|
||||||
"<package android:name=\"$gmsCoreVendor.android.gms\"/></queries>"
|
"<package android:name=\"$gmsCoreVendor.android.gms\"/></queries>",
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,23 +11,25 @@ import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
|
||||||
abstract class BaseIntegrationsPatch(
|
abstract class BaseIntegrationsPatch(
|
||||||
private val hooks: Set<IntegrationsFingerprint>
|
private val hooks: Set<IntegrationsFingerprint>,
|
||||||
) : BytecodePatch(hooks) {
|
) : BytecodePatch(hooks) {
|
||||||
|
|
||||||
@Deprecated(
|
@Deprecated(
|
||||||
"Use the constructor without the integrationsDescriptor parameter",
|
"Use the constructor without the integrationsDescriptor parameter",
|
||||||
ReplaceWith("AbstractIntegrationsPatch(hooks)")
|
ReplaceWith("BaseIntegrationsPatch(hooks)"),
|
||||||
)
|
)
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
constructor(
|
constructor(
|
||||||
integrationsDescriptor: String,
|
integrationsDescriptor: String,
|
||||||
hooks: Set<IntegrationsFingerprint>
|
hooks: Set<IntegrationsFingerprint>,
|
||||||
) : this(hooks)
|
) : this(hooks)
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) throw PatchException(
|
if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) {
|
||||||
"Integrations have not been merged yet. This patch can not succeed without merging the integrations."
|
throw PatchException(
|
||||||
)
|
"Integrations have not been merged yet. This patch can not succeed without merging the integrations.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
hooks.forEach { hook ->
|
hooks.forEach { hook ->
|
||||||
hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR)
|
hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||||
|
@ -47,14 +49,14 @@ abstract class BaseIntegrationsPatch(
|
||||||
opcodes: Iterable<Opcode?>? = null,
|
opcodes: Iterable<Opcode?>? = null,
|
||||||
strings: Iterable<String>? = null,
|
strings: Iterable<String>? = null,
|
||||||
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
|
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
|
||||||
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}
|
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {},
|
||||||
) : MethodFingerprint(
|
) : MethodFingerprint(
|
||||||
returnType,
|
returnType,
|
||||||
accessFlags,
|
accessFlags,
|
||||||
parameters,
|
parameters,
|
||||||
opcodes,
|
opcodes,
|
||||||
strings,
|
strings,
|
||||||
customFingerprint
|
customFingerprint,
|
||||||
) {
|
) {
|
||||||
fun invoke(integrationsDescriptor: String) {
|
fun invoke(integrationsDescriptor: String) {
|
||||||
result?.mutableMethod?.let { method ->
|
result?.mutableMethod?.let { method ->
|
||||||
|
@ -63,7 +65,7 @@ abstract class BaseIntegrationsPatch(
|
||||||
method.addInstruction(
|
method.addInstruction(
|
||||||
0,
|
0,
|
||||||
"sput-object v$contextRegister, " +
|
"sput-object v$contextRegister, " +
|
||||||
"$integrationsDescriptor->context:Landroid/content/Context;"
|
"$integrationsDescriptor->context:Landroid/content/Context;",
|
||||||
)
|
)
|
||||||
} ?: throw PatchException("Could not find hook target fingerprint.")
|
} ?: throw PatchException("Could not find hook target fingerprint.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import java.util.*
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
object ResourceMappingPatch : ResourcePatch() {
|
object ResourceMappingPatch : ResourcePatch() {
|
||||||
internal lateinit var resourceMappings: List<ResourceElement>
|
internal lateinit var resourceMappings: List<ResourceElement>
|
||||||
private set
|
private set
|
||||||
|
@ -17,7 +16,7 @@ object ResourceMappingPatch : ResourcePatch() {
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
// save the file in memory to concurrently read from
|
// 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
|
// create a synchronized list to store the resource mappings
|
||||||
val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
|
val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
|
||||||
|
@ -25,7 +24,9 @@ object ResourceMappingPatch : ResourcePatch() {
|
||||||
for (threadIndex in 0 until THREAD_COUNT) {
|
for (threadIndex in 0 until THREAD_COUNT) {
|
||||||
threadPoolExecutor.execute thread@{
|
threadPoolExecutor.execute thread@{
|
||||||
context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
|
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 resourcesLength = resources.length
|
||||||
val jobSize = resourcesLength / THREAD_COUNT
|
val jobSize = resourcesLength / THREAD_COUNT
|
||||||
|
|
||||||
|
|
|
@ -21,16 +21,18 @@ import java.io.Closeable
|
||||||
*/
|
*/
|
||||||
abstract class BaseSettingsResourcePatch(
|
abstract class BaseSettingsResourcePatch(
|
||||||
private val rootPreference: Pair<IntentPreference, String>? = null,
|
private val rootPreference: Pair<IntentPreference, String>? = null,
|
||||||
dependencies: Set<PatchClass> = emptySet()
|
dependencies: Set<PatchClass> = emptySet(),
|
||||||
) : ResourcePatch(
|
) : ResourcePatch(
|
||||||
dependencies = setOf(AddResourcesPatch::class) + dependencies
|
dependencies = setOf(AddResourcesPatch::class) + dependencies,
|
||||||
), MutableSet<BasePreference> by mutableSetOf(), Closeable {
|
),
|
||||||
|
MutableSet<BasePreference> by mutableSetOf(),
|
||||||
|
Closeable {
|
||||||
private lateinit var context: ResourceContext
|
private lateinit var context: ResourceContext
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
context.copyResources(
|
context.copyResources(
|
||||||
"settings",
|
"settings",
|
||||||
ResourceGroup("xml", "revanced_prefs.xml")
|
ResourceGroup("xml", "revanced_prefs.xml"),
|
||||||
)
|
)
|
||||||
|
|
||||||
this.context = context
|
this.context = context
|
||||||
|
@ -39,24 +41,34 @@ abstract class BaseSettingsResourcePatch(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
fun Node.addPreference(preference: BasePreference) {
|
fun Node.addPreference(preference: BasePreference, prepend: Boolean = false) {
|
||||||
preference.serialize(ownerDocument) { resource ->
|
preference.serialize(ownerDocument) { resource ->
|
||||||
// TODO: Currently, resources can only be added to "values", which may not be the correct place.
|
// TODO: Currently, resources can only be added to "values", which may not be the correct place.
|
||||||
// It may be necessary to ask for the desired resourceValue in the future.
|
// It may be necessary to ask for the desired resourceValue in the future.
|
||||||
AddResourcesPatch("values", resource)
|
AddResourcesPatch("values", resource)
|
||||||
}.let(this::appendChild)
|
}.let { preferenceNode ->
|
||||||
|
if (prepend && firstChild != null) {
|
||||||
|
insertBefore(preferenceNode, firstChild)
|
||||||
|
} else {
|
||||||
|
appendChild(preferenceNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the root preference to an existing fragment if needed.
|
// Add the root preference to an existing fragment if needed.
|
||||||
rootPreference?.let { (intentPreference, fragment) ->
|
rootPreference?.let { (intentPreference, fragment) ->
|
||||||
context.xmlEditor["res/xml/$fragment.xml"].use {
|
context.xmlEditor["res/xml/$fragment.xml"].use { editor ->
|
||||||
it.getNode("PreferenceScreen").addPreference(intentPreference)
|
val document = editor.file
|
||||||
|
|
||||||
|
document.getNode("PreferenceScreen").addPreference(intentPreference, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all preferences to the ReVanced fragment.
|
// Add all preferences to the ReVanced fragment.
|
||||||
context.xmlEditor["res/xml/revanced_prefs.xml"].use { editor ->
|
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) }
|
forEach { revancedPreferenceScreenNode.addPreference(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package app.revanced.patches.shared.misc.settings.preference
|
package app.revanced.patches.shared.misc.settings.preference
|
||||||
|
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
abstract class BasePreferenceScreen(
|
abstract class BasePreferenceScreen(
|
||||||
private val root: MutableSet<Screen> = mutableSetOf()
|
private val root: MutableSet<Screen> = mutableSetOf(),
|
||||||
) : Closeable {
|
) : Closeable {
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
|
@ -24,33 +25,27 @@ abstract class BasePreferenceScreen(
|
||||||
titleKey: String = "${key}_title",
|
titleKey: String = "${key}_title",
|
||||||
private val summaryKey: String? = "${key}_summary",
|
private val summaryKey: String? = "${key}_summary",
|
||||||
preferences: MutableSet<BasePreference> = mutableSetOf(),
|
preferences: MutableSet<BasePreference> = mutableSetOf(),
|
||||||
val categories: MutableSet<Category> = mutableSetOf()
|
val categories: MutableSet<Category> = mutableSetOf(),
|
||||||
|
private val sorting: Sorting = Sorting.BY_TITLE,
|
||||||
) : BasePreferenceCollection(key, titleKey, preferences) {
|
) : BasePreferenceCollection(key, titleKey, preferences) {
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize using title and summary keys with suffix "_title" and "_summary".
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
key: String? = null,
|
|
||||||
preferences: MutableSet<BasePreference> = mutableSetOf(),
|
|
||||||
categories: MutableSet<Category> = mutableSetOf()
|
|
||||||
) : this(key, key + "_title", key + "_summary", preferences, categories)
|
|
||||||
|
|
||||||
override fun transform(): PreferenceScreen {
|
override fun transform(): PreferenceScreen {
|
||||||
return PreferenceScreen(
|
return PreferenceScreen(
|
||||||
key,
|
key,
|
||||||
titleKey,
|
titleKey,
|
||||||
summaryKey,
|
summaryKey,
|
||||||
|
sorting,
|
||||||
// Screens and preferences are sorted at runtime by integrations code,
|
// Screens and preferences are sorted at runtime by integrations code,
|
||||||
// so they appear in alphabetical order for the localized language in use.
|
// so title sorting uses the localized language in use.
|
||||||
preferences = preferences + categories.map { it.transform() }
|
preferences = preferences + categories.map { it.transform() },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ensureScreenInserted() {
|
private fun ensureScreenInserted() {
|
||||||
// Add to screens if not yet done
|
// Add to screens if not yet done
|
||||||
if (!root.contains(this))
|
if (!root.contains(this)) {
|
||||||
root.add(this)
|
root.add(this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addPreferences(vararg preferences: BasePreference) {
|
fun addPreferences(vararg preferences: BasePreference) {
|
||||||
|
@ -61,13 +56,13 @@ abstract class BasePreferenceScreen(
|
||||||
open inner class Category(
|
open inner class Category(
|
||||||
key: String? = null,
|
key: String? = null,
|
||||||
titleKey: String = "${key}_title",
|
titleKey: String = "${key}_title",
|
||||||
preferences: MutableSet<BasePreference> = mutableSetOf()
|
preferences: MutableSet<BasePreference> = mutableSetOf(),
|
||||||
) : BasePreferenceCollection(key, titleKey, preferences) {
|
) : BasePreferenceCollection(key, titleKey, preferences) {
|
||||||
override fun transform(): PreferenceCategory {
|
override fun transform(): PreferenceCategory {
|
||||||
return PreferenceCategory(
|
return PreferenceCategory(
|
||||||
key,
|
key,
|
||||||
titleKey,
|
titleKey,
|
||||||
preferences = preferences
|
preferences = preferences,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +70,9 @@ abstract class BasePreferenceScreen(
|
||||||
ensureScreenInserted()
|
ensureScreenInserted()
|
||||||
|
|
||||||
// Add to the categories if not done yet.
|
// Add to the categories if not done yet.
|
||||||
if (!categories.contains(this))
|
if (!categories.contains(this)) {
|
||||||
categories.add(this)
|
categories.add(this)
|
||||||
|
}
|
||||||
|
|
||||||
this.preferences.addAll(preferences)
|
this.preferences.addAll(preferences)
|
||||||
}
|
}
|
||||||
|
@ -86,7 +82,7 @@ abstract class BasePreferenceScreen(
|
||||||
abstract class BasePreferenceCollection(
|
abstract class BasePreferenceCollection(
|
||||||
val key: String? = null,
|
val key: String? = null,
|
||||||
val titleKey: String = "${key}_title",
|
val titleKey: String = "${key}_title",
|
||||||
val preferences: MutableSet<BasePreference> = mutableSetOf()
|
val preferences: MutableSet<BasePreference> = mutableSetOf(),
|
||||||
) {
|
) {
|
||||||
abstract fun transform(): BasePreference
|
abstract fun transform(): BasePreference
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
package app.revanced.patches.shared.misc.settings.preference
|
package app.revanced.patches.shared.misc.settings.preference
|
||||||
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.IntentPreference.Intent
|
|
||||||
import app.revanced.util.resource.BaseResource
|
import app.revanced.util.resource.BaseResource
|
||||||
import org.w3c.dom.Document
|
import org.w3c.dom.Document
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A preference that opens an intent.
|
* A preference that opens an intent.
|
||||||
*
|
*
|
||||||
* @param key The preference key. If null, other parameters must be specified.
|
* @param key Optional preference key.
|
||||||
* @param titleKey The preference title key.
|
* @param titleKey The preference title key.
|
||||||
* @param summaryKey The preference summary key.
|
* @param summaryKey The preference summary key.
|
||||||
* @param tag The preference tag.
|
* @param tag The preference tag.
|
||||||
* @param intent The intent to open.
|
* @param intent The intent to open.
|
||||||
*
|
|
||||||
* @see Intent
|
|
||||||
*/
|
*/
|
||||||
class IntentPreference(
|
class IntentPreference(
|
||||||
key: String? = null,
|
key: String? = null,
|
||||||
|
@ -21,7 +18,7 @@ class IntentPreference(
|
||||||
summaryKey: String? = "${key}_summary",
|
summaryKey: String? = "${key}_summary",
|
||||||
tag: String = "Preference",
|
tag: String = "Preference",
|
||||||
val intent: Intent,
|
val intent: Intent,
|
||||||
) : BasePreference(null, titleKey, summaryKey, tag) {
|
) : BasePreference(key, titleKey, summaryKey, tag) {
|
||||||
|
|
||||||
override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) =
|
override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) =
|
||||||
super.serialize(ownerDocument, resourceCallback).apply {
|
super.serialize(ownerDocument, resourceCallback).apply {
|
||||||
|
|
|
@ -6,10 +6,12 @@ import org.w3c.dom.Document
|
||||||
/**
|
/**
|
||||||
* A non-interactive preference.
|
* A non-interactive preference.
|
||||||
*
|
*
|
||||||
|
* Typically used to present static text, but also used for custom integration code that responds to taps.
|
||||||
|
*
|
||||||
* @param key The preference key.
|
* @param key The preference key.
|
||||||
* @param summaryKey The preference summary key.
|
* @param summaryKey The preference summary key.
|
||||||
* @param tag The preference tag.
|
* @param tag The tag or full class name of the preference.
|
||||||
* @param selectable Whether the preference is selectable.
|
* @param selectable If the preference is selectable and responds to tap events.
|
||||||
*/
|
*/
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
class NonInteractivePreference(
|
class NonInteractivePreference(
|
||||||
|
|
|
@ -9,6 +9,8 @@ import org.w3c.dom.Document
|
||||||
* @param key The key of the preference. If null, other parameters must be specified.
|
* @param key The key of the preference. If null, other parameters must be specified.
|
||||||
* @param titleKey The key of the preference title.
|
* @param titleKey The key of the preference title.
|
||||||
* @param summaryKey The key of the preference summary.
|
* @param summaryKey The key of the preference summary.
|
||||||
|
* @param sorting Sorting to use. If the sorting is not [Sorting.UNSORTED],
|
||||||
|
* then the key parameter will be modified to include the sort type.
|
||||||
* @param tag The tag or full class name of the preference.
|
* @param tag The tag or full class name of the preference.
|
||||||
* @param preferences The preferences in this screen.
|
* @param preferences The preferences in this screen.
|
||||||
*/
|
*/
|
||||||
|
@ -17,14 +19,40 @@ open class PreferenceScreen(
|
||||||
key: String? = null,
|
key: String? = null,
|
||||||
titleKey: String = "${key}_title",
|
titleKey: String = "${key}_title",
|
||||||
summaryKey: String? = "${key}_summary",
|
summaryKey: String? = "${key}_summary",
|
||||||
|
sorting: Sorting = Sorting.BY_TITLE,
|
||||||
tag: String = "PreferenceScreen",
|
tag: String = "PreferenceScreen",
|
||||||
val preferences: Set<BasePreference>
|
val preferences: Set<BasePreference>,
|
||||||
) : BasePreference(key, titleKey, summaryKey, tag) {
|
// Alternatively, instead of repurposing the key for sorting,
|
||||||
|
// an extra bundle parameter can be added to the preferences XML declaration.
|
||||||
|
// This would require bundling and referencing an additional XML file
|
||||||
|
// or adding new attributes to the attrs.xml file.
|
||||||
|
// Since the key value is not currently used by integrations,
|
||||||
|
// for now it's much simpler to modify the key to include the sort parameter.
|
||||||
|
) : BasePreference(if (sorting == Sorting.UNSORTED) key else (key + sorting.keySuffix), titleKey, summaryKey, tag) {
|
||||||
override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) =
|
override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) =
|
||||||
super.serialize(ownerDocument, resourceCallback).apply {
|
super.serialize(ownerDocument, resourceCallback).apply {
|
||||||
preferences.forEach {
|
preferences.forEach {
|
||||||
appendChild(it.serialize(ownerDocument, resourceCallback))
|
appendChild(it.serialize(ownerDocument, resourceCallback))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How a PreferenceScreen should be sorted.
|
||||||
|
*/
|
||||||
|
enum class Sorting(val keySuffix: String) {
|
||||||
|
/**
|
||||||
|
* Sort by the localized preference title.
|
||||||
|
*/
|
||||||
|
BY_TITLE("_sort_by_title"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort by the preference keys.
|
||||||
|
*/
|
||||||
|
BY_KEY("_sort_by_key"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unspecified sorting.
|
||||||
|
*/
|
||||||
|
UNSORTED("_sort_by_unsorted"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.w3c.dom.Element
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Custom theme",
|
name = "Custom theme",
|
||||||
description = "Applies a custom theme.",
|
description = "Applies a custom theme.",
|
||||||
compatiblePackages = [CompatiblePackage("com.spotify.music")]
|
compatiblePackages = [CompatiblePackage("com.spotify.music")],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object CustomThemePatch : ResourcePatch() {
|
object CustomThemePatch : ResourcePatch() {
|
||||||
|
@ -19,7 +19,7 @@ object CustomThemePatch : ResourcePatch() {
|
||||||
default = "@android:color/black",
|
default = "@android:color/black",
|
||||||
title = "Primary background color",
|
title = "Primary background color",
|
||||||
description = "The background color. Can be a hex color or a resource reference.",
|
description = "The background color. Can be a hex color or a resource reference.",
|
||||||
required = true
|
required = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
private var backgroundColorSecondary by stringPatchOption(
|
private var backgroundColorSecondary by stringPatchOption(
|
||||||
|
@ -27,7 +27,7 @@ object CustomThemePatch : ResourcePatch() {
|
||||||
default = "#ff282828",
|
default = "#ff282828",
|
||||||
title = "Secondary background color",
|
title = "Secondary background color",
|
||||||
description = "The secondary background color. (e.g. search box, artist & podcast). Can be a hex color or a resource reference.",
|
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(
|
private var accentColor by stringPatchOption(
|
||||||
|
@ -35,16 +35,17 @@ object CustomThemePatch : ResourcePatch() {
|
||||||
default = "#ff1ed760",
|
default = "#ff1ed760",
|
||||||
title = "Accent color",
|
title = "Accent color",
|
||||||
description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.",
|
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(
|
private var accentColorPressed by stringPatchOption(
|
||||||
key = "accentColorPressed",
|
key = "accentColorPressed",
|
||||||
default = "#ff169c46",
|
default = "#ff169c46",
|
||||||
title = "Pressed dark theme accent color",
|
title = "Pressed dark theme accent color",
|
||||||
description = "The color when accented buttons are pressed, by default slightly darker than accent. "
|
description =
|
||||||
+ "Can be a hex color or a resource reference.",
|
"The color when accented buttons are pressed, by default slightly darker than accent. " +
|
||||||
required = true
|
"Can be a hex color or a resource reference.",
|
||||||
|
required = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
|
@ -54,23 +55,27 @@ object CustomThemePatch : ResourcePatch() {
|
||||||
val accentColorPressed = accentColorPressed!!
|
val accentColorPressed = accentColorPressed!!
|
||||||
|
|
||||||
context.xmlEditor["res/values/colors.xml"].use { editor ->
|
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) {
|
for (i in 0 until resourcesNode.childNodes.length) {
|
||||||
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
|
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
|
||||||
|
|
||||||
node.textContent = when (node.getAttribute("name")) {
|
node.textContent =
|
||||||
"dark_base_background_elevated_base", "design_dark_default_color_background",
|
when (node.getAttribute("name")) {
|
||||||
"design_dark_default_color_surface", "gray_7", "gray_background", "gray_layer",
|
"dark_base_background_elevated_base", "design_dark_default_color_background",
|
||||||
"sthlm_blk" -> backgroundColor
|
"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
|
"dark_brightaccent_background_press" -> accentColorPressed
|
||||||
else -> continue
|
else -> continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,19 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
dependencies = [IntegrationsPatch::class, SettingsPatch::class],
|
dependencies = [IntegrationsPatch::class, SettingsPatch::class],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage("com.ss.android.ugc.trill"),
|
CompatiblePackage("com.ss.android.ugc.trill"),
|
||||||
CompatiblePackage("com.zhiliaoapp.musically")
|
CompatiblePackage("com.zhiliaoapp.musically"),
|
||||||
],
|
],
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object SpoofSimPatch : BytecodePatch() {
|
object SpoofSimPatch : BytecodePatch(emptySet()) {
|
||||||
private val replacements = hashMapOf(
|
private val replacements = hashMapOf(
|
||||||
"getSimCountryIso" to "getCountryIso",
|
"getSimCountryIso" to "getCountryIso",
|
||||||
"getNetworkCountryIso" to "getCountryIso",
|
"getNetworkCountryIso" to "getCountryIso",
|
||||||
"getSimOperator" to "getOperator",
|
"getSimOperator" to "getOperator",
|
||||||
"getNetworkOperator" to "getOperator",
|
"getNetworkOperator" to "getOperator",
|
||||||
"getSimOperatorName" to "getOperatorName",
|
"getSimOperatorName" to "getOperatorName",
|
||||||
"getNetworkOperatorName" to "getOperatorName"
|
"getNetworkOperatorName" to "getOperatorName",
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
@ -85,7 +85,7 @@ object SpoofSimPatch : BytecodePatch() {
|
||||||
with(SettingsStatusLoadFingerprint.result!!.mutableMethod) {
|
with(SettingsStatusLoadFingerprint.result!!.mutableMethod) {
|
||||||
addInstruction(
|
addInstruction(
|
||||||
0,
|
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;
|
invoke-static {v$resultReg}, Lapp/revanced/integrations/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String;
|
||||||
move-result-object v$resultReg
|
move-result-object v$resultReg
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,11 +10,11 @@ import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch
|
||||||
name = "Disable dashboard ads",
|
name = "Disable dashboard ads",
|
||||||
description = "Disables ads in the dashboard.",
|
description = "Disables ads in the dashboard.",
|
||||||
compatiblePackages = [CompatiblePackage("com.tumblr")],
|
compatiblePackages = [CompatiblePackage("com.tumblr")],
|
||||||
dependencies = [TimelineFilterPatch::class]
|
dependencies = [TimelineFilterPatch::class],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object DisableDashboardAds : BytecodePatch() {
|
object DisableDashboardAds : BytecodePatch(emptySet()) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
// The timeline object types are filtered by their name in the TimelineObjectType enum.
|
// 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)
|
// This is often different from the "object_type" returned in the api (noted in comments here)
|
||||||
arrayOf(
|
arrayOf(
|
||||||
|
@ -29,7 +29,7 @@ object DisableDashboardAds : BytecodePatch() {
|
||||||
"DISPLAY_IO_INTERSCROLLER_AD", // "display_io_interscroller"
|
"DISPLAY_IO_INTERSCROLLER_AD", // "display_io_interscroller"
|
||||||
"DISPLAY_IO_HEADLINE_VIDEO_AD", // "display_io_headline_video"
|
"DISPLAY_IO_HEADLINE_VIDEO_AD", // "display_io_headline_video"
|
||||||
"FACEBOOK_BIDDAABLE", // "facebook_biddable_sdk_ad"
|
"FACEBOOK_BIDDAABLE", // "facebook_biddable_sdk_ad"
|
||||||
"GOOGLE_NATIVE" // "google_native_ad"
|
"GOOGLE_NATIVE", // "google_native_ad"
|
||||||
).forEach {
|
).forEach {
|
||||||
TimelineFilterPatch.addObjectTypeFilter(it)
|
TimelineFilterPatch.addObjectTypeFilter(it)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,10 @@ import app.revanced.patches.tumblr.featureflags.OverrideFeatureFlagsPatch
|
||||||
name = "Disable in-app update",
|
name = "Disable in-app update",
|
||||||
description = "Disables the in-app update check and update prompt.",
|
description = "Disables the in-app update check and update prompt.",
|
||||||
dependencies = [OverrideFeatureFlagsPatch::class],
|
dependencies = [OverrideFeatureFlagsPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("com.tumblr")]
|
compatiblePackages = [CompatiblePackage("com.tumblr")],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object DisableInAppUpdatePatch : BytecodePatch() {
|
object DisableInAppUpdatePatch : BytecodePatch(emptySet()) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
// Before checking for updates using Google Play core AppUpdateManager, the value of this feature flag is checked.
|
// 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.
|
// If this flag is false or the last update check was today and no update check is performed.
|
||||||
|
|
|
@ -11,10 +11,10 @@ import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch
|
||||||
name = "Disable Tumblr Live",
|
name = "Disable Tumblr Live",
|
||||||
description = "Disable the Tumblr Live tab button and dashboard carousel.",
|
description = "Disable the Tumblr Live tab button and dashboard carousel.",
|
||||||
dependencies = [OverrideFeatureFlagsPatch::class, TimelineFilterPatch::class],
|
dependencies = [OverrideFeatureFlagsPatch::class, TimelineFilterPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("com.tumblr")]
|
compatiblePackages = [CompatiblePackage("com.tumblr")],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object DisableTumblrLivePatch : BytecodePatch() {
|
object DisableTumblrLivePatch : BytecodePatch(emptySet()) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
// Hide the LIVE_MARQUEE timeline element that appears in the feed
|
// Hide the LIVE_MARQUEE timeline element that appears in the feed
|
||||||
// Called "live_marquee" in api response
|
// Called "live_marquee" in api response
|
||||||
|
|
|
@ -26,7 +26,9 @@ object AudioAdsPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(SwitchPreference("revanced_block_audio_ads"))
|
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
|
||||||
|
SwitchPreference("revanced_block_audio_ads")
|
||||||
|
)
|
||||||
|
|
||||||
// Block playAds call
|
// Block playAds call
|
||||||
with(AudioAdsPresenterPlayFingerprint.result!!) {
|
with(AudioAdsPresenterPlayFingerprint.result!!) {
|
||||||
|
|
|
@ -35,7 +35,9 @@ object VideoAdsPatch : BaseAdPatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(SwitchPreference("revanced_block_video_ads"))
|
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
|
||||||
|
SwitchPreference("revanced_block_video_ads")
|
||||||
|
)
|
||||||
|
|
||||||
/* Amazon ads SDK */
|
/* Amazon ads SDK */
|
||||||
context.blockMethods(
|
context.blockMethods(
|
||||||
|
|
|
@ -32,7 +32,9 @@ object DebugModePatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences(SwitchPreference("revanced_twitch_debug_mode"))
|
SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences(
|
||||||
|
SwitchPreference("revanced_twitch_debug_mode")
|
||||||
|
)
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
IsDebugConfigEnabledFingerprint,
|
IsDebugConfigEnabledFingerprint,
|
||||||
|
|
|
@ -25,7 +25,6 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
|
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Settings",
|
name = "Settings",
|
||||||
description = "Adds settings menu to Twitch.",
|
description = "Adds settings menu to Twitch.",
|
||||||
|
@ -62,7 +61,9 @@ object SettingsPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
PreferenceScreen.MISC.OTHER.addPreferences(SwitchPreference("revanced_debug"))
|
PreferenceScreen.MISC.OTHER.addPreferences(
|
||||||
|
SwitchPreference("revanced_debug")
|
||||||
|
)
|
||||||
|
|
||||||
// Hook onCreate to handle fragment creation
|
// Hook onCreate to handle fragment creation
|
||||||
SettingsActivityOnCreateFingerprint.result?.apply {
|
SettingsActivityOnCreateFingerprint.result?.apply {
|
||||||
|
|
|
@ -2,27 +2,36 @@ package app.revanced.patches.twitter.interaction.downloads
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
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.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
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.MethodFingerprint
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
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.ConstructMediaOptionsSheetFingerprint
|
||||||
import app.revanced.patches.twitter.interaction.downloads.fingerprints.ShowDownloadVideoUpsellBottomSheetFingerprint
|
import app.revanced.patches.twitter.interaction.downloads.fingerprints.ShowDownloadVideoUpsellBottomSheetFingerprint
|
||||||
import app.revanced.util.exception
|
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.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Unlock downloads",
|
name = "Unlock downloads",
|
||||||
description = "Unlocks the ability to download any video.",
|
description = "Unlocks the ability to download any video. GIFs can be downloaded via the menu on long press.",
|
||||||
compatiblePackages = [CompatiblePackage("com.twitter.android")]
|
compatiblePackages = [CompatiblePackage("com.twitter.android")],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object UnlockDownloadsPatch : BytecodePatch(
|
object UnlockDownloadsPatch : BytecodePatch(
|
||||||
setOf(ConstructMediaOptionsSheetFingerprint, ShowDownloadVideoUpsellBottomSheetFingerprint)
|
setOf(
|
||||||
|
ConstructMediaOptionsSheetFingerprint,
|
||||||
|
ShowDownloadVideoUpsellBottomSheetFingerprint,
|
||||||
|
BuildMediaOptionsSheetFingerprint,
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
fun MethodFingerprint.patch(getRegisterAndIndex: MethodFingerprintResult.() -> Pair<Int, Int>) = result?.let {
|
fun MethodFingerprint.patch(getRegisterAndIndex: MethodFingerprintResult.() -> Pair<Int, Int>) = result?.let {
|
||||||
|
@ -46,5 +55,29 @@ object UnlockDownloadsPatch : BytecodePatch(
|
||||||
|
|
||||||
showDownloadButtonIndex to register
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)"),
|
||||||
|
)
|
|
@ -11,12 +11,12 @@ import java.nio.file.Files
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Dynamic color",
|
name = "Dynamic color",
|
||||||
description = "Replaces the default X (Formerly Twitter) Blue with the user's Material You palette.",
|
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")
|
@Suppress("unused")
|
||||||
object DynamicColorPatch : ResourcePatch() {
|
object DynamicColorPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
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.")
|
if (!resDirectory.isDirectory) throw PatchException("The res folder can not be found.")
|
||||||
|
|
||||||
val valuesV31Directory = resDirectory.resolve("values-v31")
|
val valuesV31Directory = resDirectory.resolve("values-v31")
|
||||||
|
@ -28,7 +28,7 @@ object DynamicColorPatch : ResourcePatch() {
|
||||||
listOf(valuesV31Directory, valuesNightV31Directory).forEach { it ->
|
listOf(valuesV31Directory, valuesNightV31Directory).forEach { it ->
|
||||||
val colorsXml = it.resolve("colors.xml")
|
val colorsXml = it.resolve("colors.xml")
|
||||||
|
|
||||||
if(!colorsXml.exists()) {
|
if (!colorsXml.exists()) {
|
||||||
FileWriter(colorsXml).use {
|
FileWriter(colorsXml).use {
|
||||||
it.write("<?xml version=\"1.0\" encoding=\"utf-8\"?><resources></resources>")
|
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_30" to "@android:color/system_accent1_100",
|
||||||
"twitter_blue_opacity_50" to "@android:color/system_accent1_200",
|
"twitter_blue_opacity_50" to "@android:color/system_accent1_200",
|
||||||
"twitter_blue_opacity_58" to "@android:color/system_accent1_300",
|
"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) ->
|
).forEach { (k, v) ->
|
||||||
val colorElement = document.createElement("color")
|
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_30" to "@android:color/system_accent1_50",
|
||||||
"twitter_blue_opacity_50" to "@android:color/system_accent1_100",
|
"twitter_blue_opacity_50" to "@android:color/system_accent1_100",
|
||||||
"twitter_blue_opacity_58" to "@android:color/system_accent1_200",
|
"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) ->
|
).forEach { (k, v) ->
|
||||||
val colorElement = document.createElement("color")
|
val colorElement = document.createElement("color")
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patches.twitter.misc.hook.json.JsonHookPatch
|
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) =
|
override fun execute(context: BytecodeContext) =
|
||||||
JsonHookPatch.hooks.addHook(JsonHookPatch.Hook(context, hookClassDescriptor))
|
JsonHookPatch.hooks.addHook(JsonHookPatch.Hook(context, hookClassDescriptor))
|
||||||
}
|
}
|
|
@ -7,9 +7,8 @@ import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatch
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Hide ads",
|
name = "Hide ads",
|
||||||
description = "Hides ads.",
|
|
||||||
dependencies = [JsonHookPatch::class],
|
dependencies = [JsonHookPatch::class],
|
||||||
compatiblePackages = [CompatiblePackage("com.twitter.android")]
|
compatiblePackages = [CompatiblePackage("com.twitter.android")],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@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;")
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;"),
|
||||||
|
)
|
|
@ -1,20 +1,20 @@
|
||||||
package app.revanced.patches.vsco.misc.pro
|
package app.revanced.patches.vsco.misc.pro
|
||||||
|
|
||||||
import app.revanced.util.exception
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.vsco.misc.pro.fingerprints.RevCatSubscriptionFingerprint
|
import app.revanced.patches.vsco.misc.pro.fingerprints.RevCatSubscriptionFingerprint
|
||||||
|
import app.revanced.util.exception
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Unlock pro",
|
name = "Unlock pro",
|
||||||
description = "Unlocks pro features.",
|
description = "Unlocks pro features.",
|
||||||
compatiblePackages = [CompatiblePackage("com.vsco.cam")]
|
compatiblePackages = [CompatiblePackage("com.vsco.cam", ["345"])],
|
||||||
)
|
)
|
||||||
object UnlockProPatch : BytecodePatch(
|
object UnlockProPatch : BytecodePatch(
|
||||||
setOf(RevCatSubscriptionFingerprint)
|
setOf(RevCatSubscriptionFingerprint),
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
RevCatSubscriptionFingerprint.result?.mutableMethod?.apply {
|
RevCatSubscriptionFingerprint.result?.mutableMethod?.apply {
|
||||||
|
@ -23,7 +23,7 @@ object UnlockProPatch : BytecodePatch(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
const p1, 0x1
|
const p1, 0x1
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
} ?: throw RevCatSubscriptionFingerprint.exception
|
} ?: throw RevCatSubscriptionFingerprint.exception
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package app.revanced.patches.youtube.ad.general
|
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.data.BytecodeContext
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
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.shared.misc.fix.verticalscroll.VerticalScrollPatch
|
||||||
import app.revanced.patches.youtube.ad.getpremium.HideGetPremiumPatch
|
import app.revanced.patches.youtube.ad.getpremium.HideGetPremiumPatch
|
||||||
import app.revanced.patches.youtube.misc.fix.backtoexitgesture.FixBackToExitGesturePatch
|
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.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i
|
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
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,
|
HideGetPremiumPatch::class,
|
||||||
HideAdsResourcePatch::class,
|
HideAdsResourcePatch::class,
|
||||||
VerticalScrollPatch::class,
|
VerticalScrollPatch::class,
|
||||||
FixBackToExitGesturePatch::class
|
FixBackToExitGesturePatch::class,
|
||||||
],
|
],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube", [
|
"com.google.android.youtube",
|
||||||
|
[
|
||||||
"18.32.39",
|
"18.32.39",
|
||||||
"18.37.36",
|
"18.37.36",
|
||||||
"18.38.44",
|
"18.38.44",
|
||||||
|
@ -37,30 +38,33 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
"19.02.39",
|
"19.02.39",
|
||||||
"19.03.35",
|
"19.03.35",
|
||||||
"19.03.36",
|
"19.03.36",
|
||||||
"19.04.37"
|
"19.04.37",
|
||||||
]
|
],
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object HideAdsPatch : BytecodePatch() {
|
object HideAdsPatch : BytecodePatch(emptySet()) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
context.classes.forEach { classDef ->
|
context.classes.forEach { classDef ->
|
||||||
classDef.methods.forEach { method ->
|
classDef.methods.forEach { method ->
|
||||||
with(method.implementation) {
|
with(method.implementation) {
|
||||||
this?.instructions?.forEachIndexed { index, instruction ->
|
this?.instructions?.forEachIndexed { index, instruction ->
|
||||||
if (instruction.opcode != Opcode.CONST)
|
if (instruction.opcode != Opcode.CONST) {
|
||||||
return@forEachIndexed
|
return@forEachIndexed
|
||||||
|
}
|
||||||
// Instruction to store the id adAttribution into a register
|
// 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
|
return@forEachIndexed
|
||||||
|
}
|
||||||
|
|
||||||
val insertIndex = index + 1
|
val insertIndex = index + 1
|
||||||
|
|
||||||
// Call to get the view with the id adAttribution
|
// Call to get the view with the id adAttribution
|
||||||
with(instructions.elementAt(insertIndex)) {
|
with(instructions.elementAt(insertIndex)) {
|
||||||
if (opcode != Opcode.INVOKE_VIRTUAL)
|
if (opcode != Opcode.INVOKE_VIRTUAL) {
|
||||||
return@forEachIndexed
|
return@forEachIndexed
|
||||||
|
}
|
||||||
|
|
||||||
// Hide the view
|
// Hide the view
|
||||||
val viewRegister = (this as Instruction35c).registerC
|
val viewRegister = (this as Instruction35c).registerC
|
||||||
|
@ -71,7 +75,7 @@ object HideAdsPatch : BytecodePatch() {
|
||||||
insertIndex,
|
insertIndex,
|
||||||
viewRegister,
|
viewRegister,
|
||||||
"Lapp/revanced/integrations/youtube/patches/components/AdsFilter;",
|
"Lapp/revanced/integrations/youtube/patches/components/AdsFilter;",
|
||||||
"hideAdAttributionView"
|
"hideAdAttributionView",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch.PreferenceScreen
|
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
@ -27,7 +26,7 @@ object HideAdsResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
PreferenceScreen.ADS.addPreferences(
|
SettingsPatch.PreferenceScreen.ADS.addPreferences(
|
||||||
SwitchPreference("revanced_hide_general_ads"),
|
SwitchPreference("revanced_hide_general_ads"),
|
||||||
SwitchPreference("revanced_hide_fullscreen_ads"),
|
SwitchPreference("revanced_hide_fullscreen_ads"),
|
||||||
SwitchPreference("revanced_hide_buttoned_ads"),
|
SwitchPreference("revanced_hide_buttoned_ads"),
|
||||||
|
|
|
@ -44,7 +44,9 @@ object HideGetPremiumPatch : BytecodePatch(setOf(GetPremiumViewFingerprint)) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.addPreferences(SwitchPreference("revanced_hide_get_premium"))
|
SettingsPatch.PreferenceScreen.ADS.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_get_premium")
|
||||||
|
)
|
||||||
|
|
||||||
GetPremiumViewFingerprint.result?.let {
|
GetPremiumViewFingerprint.result?.let {
|
||||||
it.mutableMethod.apply {
|
it.mutableMethod.apply {
|
||||||
|
|
|
@ -49,7 +49,9 @@ object VideoAdsPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.addPreferences(SwitchPreference("revanced_hide_video_ads"))
|
SettingsPatch.PreferenceScreen.ADS.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_video_ads")
|
||||||
|
)
|
||||||
|
|
||||||
val loadVideoAdsFingerprintMethod = LoadVideoAdsFingerprint.result!!.mutableMethod
|
val loadVideoAdsFingerprintMethod = LoadVideoAdsFingerprint.result!!.mutableMethod
|
||||||
|
|
||||||
|
|
|
@ -13,28 +13,29 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||||
dependencies = [
|
dependencies = [
|
||||||
CopyVideoUrlResourcePatch::class,
|
CopyVideoUrlResourcePatch::class,
|
||||||
PlayerControlsBytecodePatch::class,
|
PlayerControlsBytecodePatch::class,
|
||||||
VideoInformationPatch::class
|
VideoInformationPatch::class,
|
||||||
],
|
],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube", [
|
"com.google.android.youtube",
|
||||||
|
[
|
||||||
"18.48.39",
|
"18.48.39",
|
||||||
"18.49.37",
|
"18.49.37",
|
||||||
"19.01.34",
|
"19.01.34",
|
||||||
"19.02.39",
|
"19.02.39",
|
||||||
"19.03.35",
|
"19.03.35",
|
||||||
"19.03.36",
|
"19.03.36",
|
||||||
"19.04.37"
|
"19.04.37",
|
||||||
]
|
],
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object CopyVideoUrlBytecodePatch : BytecodePatch() {
|
object CopyVideoUrlBytecodePatch : BytecodePatch(emptySet()) {
|
||||||
private const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/youtube/videoplayer"
|
private const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/youtube/videoplayer"
|
||||||
private val BUTTONS_DESCRIPTORS = listOf(
|
private val BUTTONS_DESCRIPTORS = listOf(
|
||||||
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlButton;",
|
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlButton;",
|
||||||
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;"
|
"$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;",
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import app.revanced.patcher.data.ResourceContext
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
|
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
|
@ -22,14 +21,9 @@ internal object CopyVideoUrlResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
PreferenceScreen(
|
SwitchPreference("revanced_copy_video_url"),
|
||||||
"revanced_copy_video_url_preference_screen",
|
SwitchPreference("revanced_copy_video_url_timestamp")
|
||||||
preferences = setOf(
|
|
||||||
SwitchPreference("revanced_copy_video_url"),
|
|
||||||
SwitchPreference("revanced_copy_video_url_timestamp")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
context.copyResources(
|
context.copyResources(
|
||||||
|
@ -40,8 +34,6 @@ internal object CopyVideoUrlResourcePatch : ResourcePatch() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
AddResourcesPatch(this::class)
|
|
||||||
|
|
||||||
BottomControlsResourcePatch.addControls("copyvideourl")
|
BottomControlsResourcePatch.addControls("copyvideourl")
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -50,7 +50,9 @@ object RemoveViewerDiscretionDialogPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_remove_viewer_discretion_dialog"))
|
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||||
|
SwitchPreference("revanced_remove_viewer_discretion_dialog")
|
||||||
|
)
|
||||||
|
|
||||||
CreateDialogFingerprint.result?.mutableMethod?.apply {
|
CreateDialogFingerprint.result?.mutableMethod?.apply {
|
||||||
val showDialogIndex = implementation!!.instructions.lastIndex - 2
|
val showDialogIndex = implementation!!.instructions.lastIndex - 2
|
||||||
|
|
|
@ -13,24 +13,25 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||||
dependencies = [
|
dependencies = [
|
||||||
ExternalDownloadsResourcePatch::class,
|
ExternalDownloadsResourcePatch::class,
|
||||||
PlayerControlsBytecodePatch::class,
|
PlayerControlsBytecodePatch::class,
|
||||||
VideoInformationPatch::class
|
VideoInformationPatch::class,
|
||||||
],
|
],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube", [
|
"com.google.android.youtube",
|
||||||
|
[
|
||||||
"18.48.39",
|
"18.48.39",
|
||||||
"18.49.37",
|
"18.49.37",
|
||||||
"19.01.34",
|
"19.01.34",
|
||||||
"19.02.39",
|
"19.02.39",
|
||||||
"19.03.35",
|
"19.03.35",
|
||||||
"19.03.36",
|
"19.03.36",
|
||||||
"19.04.37"
|
"19.04.37",
|
||||||
]
|
],
|
||||||
),
|
),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object ExternalDownloadsBytecodePatch : BytecodePatch() {
|
object ExternalDownloadsBytecodePatch : BytecodePatch(emptySet()) {
|
||||||
private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
|
private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
@ -39,13 +40,15 @@ object ExternalDownloadsBytecodePatch : BytecodePatch() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PlayerControlsBytecodePatch.initializeControl(
|
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
|
add code to change the visibility of the control
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PlayerControlsBytecodePatch.injectVisibilityCheckCall(
|
PlayerControlsBytecodePatch.injectVisibilityCheckCall(
|
||||||
"$BUTTON_DESCRIPTOR->changeVisibility(Z)V")
|
"$BUTTON_DESCRIPTOR->changeVisibility(Z)V",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@ import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||||
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
|
import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch
|
||||||
|
@ -18,25 +19,26 @@ import app.revanced.util.copyResources
|
||||||
BottomControlsResourcePatch::class,
|
BottomControlsResourcePatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
AddResourcesPatch::class,
|
AddResourcesPatch::class,
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
internal object ExternalDownloadsResourcePatch : ResourcePatch() {
|
internal object ExternalDownloadsResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
"revanced_external_downloader_preference_screen",
|
key = "revanced_external_downloader_screen",
|
||||||
|
sorting = Sorting.UNSORTED,
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_external_downloader"),
|
SwitchPreference("revanced_external_downloader"),
|
||||||
TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT)
|
TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
context.copyResources(
|
context.copyResources(
|
||||||
"downloads",
|
"downloads",
|
||||||
ResourceGroup("drawable", "revanced_yt_download_button.xml")
|
ResourceGroup("drawable", "revanced_yt_download_button.xml"),
|
||||||
)
|
)
|
||||||
|
|
||||||
BottomControlsResourcePatch.addControls("downloads")
|
BottomControlsResourcePatch.addControls("downloads")
|
||||||
|
|
|
@ -50,7 +50,7 @@ object DisablePreciseSeekingGesturePatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
|
SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences(
|
||||||
SwitchPreference("revanced_disable_precise_seeking_gesture")
|
SwitchPreference("revanced_disable_precise_seeking_gesture")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,9 @@ object EnableSeekbarTappingPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_seekbar_tapping"))
|
SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences(
|
||||||
|
SwitchPreference("revanced_seekbar_tapping")
|
||||||
|
)
|
||||||
|
|
||||||
// Find the required methods to tap the seekbar.
|
// Find the required methods to tap the seekbar.
|
||||||
val seekbarTappingMethods = OnTouchEventHandlerFingerprint.result?.let {
|
val seekbarTappingMethods = OnTouchEventHandlerFingerprint.result?.let {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Enable slide to seek",
|
name = "Enable slide to seek",
|
||||||
description = "Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.",
|
description = "Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.",
|
||||||
dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
|
dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
|
@ -50,7 +50,9 @@ object EnableSlideToSeekPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_slide_to_seek"))
|
SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences(
|
||||||
|
SwitchPreference("revanced_slide_to_seek")
|
||||||
|
)
|
||||||
|
|
||||||
arrayOf(
|
arrayOf(
|
||||||
// Restore the behaviour to slide to seek.
|
// Restore the behaviour to slide to seek.
|
||||||
|
|
|
@ -5,7 +5,6 @@ import app.revanced.patcher.patch.ResourcePatch
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
|
@ -13,27 +12,22 @@ import app.revanced.util.ResourceGroup
|
||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
dependencies = [SettingsPatch::class, AddResourcesPatch::class]
|
dependencies = [SettingsPatch::class, AddResourcesPatch::class],
|
||||||
)
|
)
|
||||||
internal object SwipeControlsResourcePatch : ResourcePatch() {
|
internal object SwipeControlsResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
|
SettingsPatch.PreferenceScreen.SWIPE_CONTROLS.addPreferences(
|
||||||
PreferenceScreen(
|
SwitchPreference("revanced_swipe_brightness"),
|
||||||
key = "revanced_swipe_controls_preference_screen",
|
SwitchPreference("revanced_swipe_volume"),
|
||||||
preferences = setOf(
|
SwitchPreference("revanced_swipe_press_to_engage"),
|
||||||
SwitchPreference("revanced_swipe_brightness"),
|
SwitchPreference("revanced_swipe_haptic_feedback"),
|
||||||
SwitchPreference("revanced_swipe_volume"),
|
SwitchPreference("revanced_swipe_save_and_restore_brightness"),
|
||||||
SwitchPreference("revanced_swipe_press_to_engage"),
|
TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER),
|
||||||
SwitchPreference("revanced_swipe_haptic_feedback"),
|
TextPreference("revanced_swipe_text_overlay_size", inputType = InputType.NUMBER),
|
||||||
SwitchPreference("revanced_swipe_save_and_restore_brightness"),
|
TextPreference("revanced_swipe_overlay_background_alpha", inputType = InputType.NUMBER),
|
||||||
TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER),
|
TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER),
|
||||||
TextPreference("revanced_swipe_text_overlay_size", inputType = InputType.NUMBER),
|
|
||||||
TextPreference("revanced_swipe_overlay_background_alpha", inputType = InputType.NUMBER),
|
|
||||||
TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
context.copyResources(
|
context.copyResources(
|
||||||
|
@ -43,8 +37,8 @@ internal object SwipeControlsResourcePatch : ResourcePatch() {
|
||||||
"revanced_ic_sc_brightness_auto.xml",
|
"revanced_ic_sc_brightness_auto.xml",
|
||||||
"revanced_ic_sc_brightness_manual.xml",
|
"revanced_ic_sc_brightness_manual.xml",
|
||||||
"revanced_ic_sc_volume_mute.xml",
|
"revanced_ic_sc_volume_mute.xml",
|
||||||
"revanced_ic_sc_volume_normal.xml"
|
"revanced_ic_sc_volume_normal.xml",
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ object AutoCaptionsPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_auto_captions"))
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_auto_captions")
|
||||||
|
)
|
||||||
|
|
||||||
mapOf(
|
mapOf(
|
||||||
StartVideoInformerFingerprint to 0,
|
StartVideoInformerFingerprint to 0,
|
||||||
|
|
|
@ -15,9 +15,9 @@ import java.nio.file.Files
|
||||||
name = "Custom branding",
|
name = "Custom branding",
|
||||||
description = "Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.",
|
description = "Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.",
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage("com.google.android.youtube")
|
CompatiblePackage("com.google.android.youtube"),
|
||||||
],
|
],
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object CustomBrandingPatch : ResourcePatch() {
|
object CustomBrandingPatch : ResourcePatch() {
|
||||||
|
@ -28,7 +28,7 @@ object CustomBrandingPatch : ResourcePatch() {
|
||||||
"adaptiveproduct_youtube_background_color_108",
|
"adaptiveproduct_youtube_background_color_108",
|
||||||
"adaptiveproduct_youtube_foreground_color_108",
|
"adaptiveproduct_youtube_foreground_color_108",
|
||||||
"ic_launcher",
|
"ic_launcher",
|
||||||
"ic_launcher_round"
|
"ic_launcher_round",
|
||||||
).map { "$it.png" }.toTypedArray()
|
).map { "$it.png" }.toTypedArray()
|
||||||
|
|
||||||
private val mipmapDirectories = arrayOf(
|
private val mipmapDirectories = arrayOf(
|
||||||
|
@ -36,7 +36,7 @@ object CustomBrandingPatch : ResourcePatch() {
|
||||||
"xxhdpi",
|
"xxhdpi",
|
||||||
"xhdpi",
|
"xhdpi",
|
||||||
"hdpi",
|
"hdpi",
|
||||||
"mdpi"
|
"mdpi",
|
||||||
).map { "mipmap-$it" }
|
).map { "mipmap-$it" }
|
||||||
|
|
||||||
private var appName by stringPatchOption(
|
private var appName by stringPatchOption(
|
||||||
|
@ -49,7 +49,7 @@ object CustomBrandingPatch : ResourcePatch() {
|
||||||
"YouTube" to "YouTube",
|
"YouTube" to "YouTube",
|
||||||
),
|
),
|
||||||
title = "App name",
|
title = "App name",
|
||||||
description = "The name of the app."
|
description = "The name of the app.",
|
||||||
)
|
)
|
||||||
|
|
||||||
private var icon by stringPatchOption(
|
private var icon by stringPatchOption(
|
||||||
|
@ -58,14 +58,16 @@ object CustomBrandingPatch : ResourcePatch() {
|
||||||
values = mapOf("ReVanced Logo" to REVANCED_ICON),
|
values = mapOf("ReVanced Logo" to REVANCED_ICON),
|
||||||
title = "App icon",
|
title = "App icon",
|
||||||
description = """
|
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" }}
|
${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" }}
|
${iconResourceFileNames.joinToString("\n") { "- $it" }}
|
||||||
""".trimIndentMultiline()
|
""".trimIndentMultiline(),
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
|
@ -73,12 +75,13 @@ object CustomBrandingPatch : ResourcePatch() {
|
||||||
// Change the app icon.
|
// Change the app icon.
|
||||||
mipmapDirectories.map { directory ->
|
mipmapDirectories.map { directory ->
|
||||||
ResourceGroup(
|
ResourceGroup(
|
||||||
directory, *iconResourceFileNames
|
directory,
|
||||||
|
*iconResourceFileNames,
|
||||||
)
|
)
|
||||||
}.let { resourceGroups ->
|
}.let { resourceGroups ->
|
||||||
if (icon != REVANCED_ICON) {
|
if (icon != REVANCED_ICON) {
|
||||||
val path = File(icon)
|
val path = File(icon)
|
||||||
val resourceDirectory = context["res"]
|
val resourceDirectory = context.get("res")
|
||||||
|
|
||||||
resourceGroups.forEach { group ->
|
resourceGroups.forEach { group ->
|
||||||
val fromDirectory = path.resolve(group.resourceDirectoryName)
|
val fromDirectory = path.resolve(group.resourceDirectoryName)
|
||||||
|
@ -87,23 +90,25 @@ object CustomBrandingPatch : ResourcePatch() {
|
||||||
group.resources.forEach { iconFileName ->
|
group.resources.forEach { iconFileName ->
|
||||||
Files.write(
|
Files.write(
|
||||||
toDirectory.resolve(iconFileName).toPath(),
|
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 ->
|
appName?.let { name ->
|
||||||
// Change the app name.
|
// Change the app name.
|
||||||
val manifest = context["AndroidManifest.xml"]
|
val manifest = context.get("AndroidManifest.xml")
|
||||||
manifest.writeText(
|
manifest.writeText(
|
||||||
manifest.readText()
|
manifest.readText()
|
||||||
.replace(
|
.replace(
|
||||||
"android:label=\"@string/application_name",
|
"android:label=\"@string/application_name",
|
||||||
"android:label=\"$name"
|
"android:label=\"$name",
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,67 +15,74 @@ import java.io.File
|
||||||
name = "Change header",
|
name = "Change header",
|
||||||
description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.",
|
description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.",
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage("com.google.android.youtube")
|
CompatiblePackage("com.google.android.youtube"),
|
||||||
],
|
],
|
||||||
use = false
|
use = false,
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object ChangeHeaderPatch : ResourcePatch() {
|
object ChangeHeaderPatch : ResourcePatch() {
|
||||||
private const val HEADER_NAME = "yt_wordmark_header"
|
private const val HEADER_FILE_NAME = "yt_wordmark_header"
|
||||||
private const val PREMIUM_HEADER_NAME = "yt_premium_wordmark_header"
|
private const val PREMIUM_HEADER_FILE_NAME = "yt_premium_wordmark_header"
|
||||||
private const val REVANCED_HEADER_NAME = "ReVanced"
|
|
||||||
private const val REVANCED_BORDERLESS_HEADER_NAME = "ReVanced (borderless logo)"
|
|
||||||
|
|
||||||
private val targetResourceDirectoryNames = arrayOf(
|
private const val HEADER_OPTION = "header*"
|
||||||
"xxxhdpi",
|
private const val PREMIUM_HEADER_OPTION = "premium*header"
|
||||||
"xxhdpi",
|
private const val REVANCED_HEADER_OPTION = "revanced*"
|
||||||
"xhdpi",
|
private const val REVANCED_BORDERLESS_HEADER_OPTION = "revanced*borderless"
|
||||||
"mdpi",
|
|
||||||
"hdpi",
|
private val targetResourceDirectoryNames = mapOf(
|
||||||
).map { dpi ->
|
"xxxhdpi" to "512px x 192px",
|
||||||
"drawable-$dpi"
|
"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 variants = arrayOf("light", "dark")
|
||||||
|
|
||||||
private val header by stringPatchOption(
|
private val header by stringPatchOption(
|
||||||
key = "header",
|
key = "header",
|
||||||
default = REVANCED_BORDERLESS_HEADER_NAME,
|
default = REVANCED_BORDERLESS_HEADER_OPTION,
|
||||||
values = mapOf(
|
values = mapOf(
|
||||||
"YouTube" to HEADER_NAME,
|
"YouTube" to HEADER_OPTION,
|
||||||
"YouTube Premium" to PREMIUM_HEADER_NAME,
|
"YouTube Premium" to PREMIUM_HEADER_OPTION,
|
||||||
"ReVanced" to REVANCED_HEADER_NAME,
|
"ReVanced" to REVANCED_HEADER_OPTION,
|
||||||
"ReVanced (borderless logo)" to REVANCED_BORDERLESS_HEADER_NAME,
|
"ReVanced (borderless logo)" to REVANCED_BORDERLESS_HEADER_OPTION,
|
||||||
),
|
),
|
||||||
title = "Header",
|
title = "Header",
|
||||||
description = """
|
description = """
|
||||||
Either a header name or a path to a custom header folder to use in the top bar.
|
The header to apply to the app.
|
||||||
The path to a folder must contain one or more of the following folders matching the DPI of your device:
|
|
||||||
|
|
||||||
${targetResourceDirectoryNames.joinToString("\n") { "- $it" }}
|
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:
|
||||||
|
|
||||||
These folders must contain the following files:
|
${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }}
|
||||||
|
|
||||||
${variants.joinToString("\n") { variant -> "- ${HEADER_NAME}_$variant.png" }}
|
Each of the folders must contain all of the following files:
|
||||||
|
|
||||||
|
${variants.joinToString("\n") { variant -> "- ${HEADER_FILE_NAME}_$variant.png" }}
|
||||||
|
|
||||||
|
The image dimensions must be as follows:
|
||||||
|
${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")}
|
||||||
""".trimIndentMultiline(),
|
""".trimIndentMultiline(),
|
||||||
required = true,
|
required = true,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
// The directories to copy the header to.
|
// The directories to copy the header to.
|
||||||
val targetResourceDirectories = targetResourceDirectoryNames.mapNotNull {
|
val targetResourceDirectories = targetResourceDirectoryNames.keys.mapNotNull {
|
||||||
context["res"].resolve(it).takeIf(File::exists)
|
context.get("res").resolve(it).takeIf(File::exists)
|
||||||
}
|
}
|
||||||
// The files to replace in the target directories.
|
// The files to replace in the target directories.
|
||||||
val targetResourceFiles = targetResourceDirectoryNames.map { directoryName ->
|
val targetResourceFiles = targetResourceDirectoryNames.keys.map { directoryName ->
|
||||||
ResourceGroup(
|
ResourceGroup(
|
||||||
directoryName,
|
directoryName,
|
||||||
*variants.map { variant -> "${HEADER_NAME}_$variant.png" }.toTypedArray()
|
*variants.map { variant -> "${HEADER_FILE_NAME}_$variant.png" }.toTypedArray(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that overwrites both header variants from [from] to [to] in the target resource directories.
|
* A function that overwrites both header variants in the target resource directories.
|
||||||
*/
|
*/
|
||||||
val overwriteFromTo: (String, String) -> Unit = { from: String, to: String ->
|
val overwriteFromTo: (String, String) -> Unit = { from: String, to: String ->
|
||||||
targetResourceDirectories.forEach { directory ->
|
targetResourceDirectories.forEach { directory ->
|
||||||
|
@ -89,8 +96,8 @@ object ChangeHeaderPatch : ResourcePatch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions to overwrite the header to the different variants.
|
// Functions to overwrite the header to the different variants.
|
||||||
val toPremium = { overwriteFromTo(PREMIUM_HEADER_NAME, HEADER_NAME) }
|
val toPremium = { overwriteFromTo(PREMIUM_HEADER_FILE_NAME, HEADER_FILE_NAME) }
|
||||||
val toHeader = { overwriteFromTo(HEADER_NAME, PREMIUM_HEADER_NAME) }
|
val toHeader = { overwriteFromTo(HEADER_FILE_NAME, PREMIUM_HEADER_FILE_NAME) }
|
||||||
val toReVanced = {
|
val toReVanced = {
|
||||||
// Copy the ReVanced header to the resource directories.
|
// Copy the ReVanced header to the resource directories.
|
||||||
targetResourceFiles.forEach { context.copyResources("change-header/revanced", it) }
|
targetResourceFiles.forEach { context.copyResources("change-header/revanced", it) }
|
||||||
|
@ -106,32 +113,38 @@ object ChangeHeaderPatch : ResourcePatch() {
|
||||||
toHeader()
|
toHeader()
|
||||||
}
|
}
|
||||||
val toCustom = {
|
val toCustom = {
|
||||||
var copiedReplacementImages = false
|
val sourceFolders = File(header!!).listFiles { file -> file.isDirectory }
|
||||||
// For all the resource groups in the custom header folder, copy them to the resource directories.
|
?: throw PatchException("The provided path is not a directory: $header")
|
||||||
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
|
|
||||||
|
|
||||||
folder.listFiles { file -> file.isFile }?.forEach {
|
var copiedFiles = false
|
||||||
val targetResourceFile = targetDirectory.resolve(it.name)
|
|
||||||
|
|
||||||
it.copyTo(targetResourceFile, true)
|
// For each source folder, copy the files to the target resource directories.
|
||||||
copiedReplacementImages = true
|
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.
|
// Overwrite the premium with the custom header as well.
|
||||||
toHeader()
|
toHeader()
|
||||||
}
|
}
|
||||||
|
|
||||||
when (header) {
|
when (header) {
|
||||||
HEADER_NAME -> toHeader
|
HEADER_OPTION -> toHeader
|
||||||
PREMIUM_HEADER_NAME -> toPremium
|
PREMIUM_HEADER_OPTION -> toPremium
|
||||||
REVANCED_HEADER_NAME -> toReVanced
|
REVANCED_HEADER_OPTION -> toReVanced
|
||||||
REVANCED_BORDERLESS_HEADER_NAME -> toReVancedBorderless
|
REVANCED_BORDERLESS_HEADER_OPTION -> toReVancedBorderless
|
||||||
else -> toCustom
|
else -> toCustom
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,11 @@ object HideButtonsPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
"revanced_hide_buttons_preference_screen",
|
"revanced_hide_buttons_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_hide_like_dislike_button"),
|
SwitchPreference("revanced_hide_like_dislike_button"),
|
||||||
SwitchPreference("revanced_hide_live_chat_button"),
|
|
||||||
SwitchPreference("revanced_hide_share_button"),
|
SwitchPreference("revanced_hide_share_button"),
|
||||||
SwitchPreference("revanced_hide_report_button"),
|
SwitchPreference("revanced_hide_report_button"),
|
||||||
SwitchPreference("revanced_hide_remix_button"),
|
SwitchPreference("revanced_hide_remix_button"),
|
||||||
|
|
|
@ -57,7 +57,9 @@ object HideAutoplayButtonPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_autoplay_button"))
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_autoplay_button")
|
||||||
|
)
|
||||||
|
|
||||||
LayoutConstructorFingerprint.result?.mutableMethod?.apply {
|
LayoutConstructorFingerprint.result?.mutableMethod?.apply {
|
||||||
val layoutGenMethodInstructions = implementation!!.instructions
|
val layoutGenMethodInstructions = implementation!!.instructions
|
||||||
|
|
|
@ -48,7 +48,9 @@ object HideCaptionsButtonPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_captions_button"))
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_captions_button")
|
||||||
|
)
|
||||||
|
|
||||||
val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod
|
val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,19 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
dependencies = [
|
dependencies = [
|
||||||
IntegrationsPatch::class,
|
IntegrationsPatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
AddResourcesPatch::class
|
AddResourcesPatch::class,
|
||||||
],
|
],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage("com.google.android.youtube")
|
CompatiblePackage("com.google.android.youtube"),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
object HideCastButtonPatch : BytecodePatch() {
|
object HideCastButtonPatch : BytecodePatch(emptySet()) {
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_cast_button"))
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_cast_button")
|
||||||
|
)
|
||||||
|
|
||||||
val buttonClass = context.findClass("MediaRouteButton")
|
val buttonClass = context.findClass("MediaRouteButton")
|
||||||
?: throw PatchException("MediaRouteButton class not found.")
|
?: throw PatchException("MediaRouteButton class not found.")
|
||||||
|
@ -38,7 +40,7 @@ object HideCastButtonPatch : BytecodePatch() {
|
||||||
"""
|
"""
|
||||||
invoke-static {p1}, Lapp/revanced/integrations/youtube/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I
|
invoke-static {p1}, Lapp/revanced/integrations/youtube/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I
|
||||||
move-result p1
|
move-result p1
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
} ?: throw PatchException("setVisibility method not found.")
|
} ?: throw PatchException("setVisibility method not found.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.*
|
import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.*
|
||||||
import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
||||||
|
@ -24,7 +25,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
IntegrationsPatch::class,
|
IntegrationsPatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
ResolvePivotBarFingerprintsPatch::class,
|
ResolvePivotBarFingerprintsPatch::class,
|
||||||
AddResourcesPatch::class
|
AddResourcesPatch::class,
|
||||||
],
|
],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
|
@ -42,14 +43,14 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
"19.02.39",
|
"19.02.39",
|
||||||
"19.03.35",
|
"19.03.35",
|
||||||
"19.03.36",
|
"19.03.36",
|
||||||
"19.04.37"
|
"19.04.37",
|
||||||
]
|
],
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object NavigationButtonsPatch : BytecodePatch(
|
object NavigationButtonsPatch : BytecodePatch(
|
||||||
setOf(AddCreateButtonViewFingerprint)
|
setOf(AddCreateButtonViewFingerprint),
|
||||||
) {
|
) {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;"
|
"Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;"
|
||||||
|
@ -57,17 +58,18 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
key = "revanced_navigation_buttons_preference_screen",
|
key = "revanced_navigation_buttons_screen",
|
||||||
|
sorting = Sorting.UNSORTED,
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_hide_home_button"),
|
SwitchPreference("revanced_hide_home_button"),
|
||||||
SwitchPreference("revanced_hide_shorts_button"),
|
SwitchPreference("revanced_hide_shorts_button"),
|
||||||
SwitchPreference("revanced_hide_subscriptions_button"),
|
|
||||||
SwitchPreference("revanced_hide_create_button"),
|
SwitchPreference("revanced_hide_create_button"),
|
||||||
|
SwitchPreference("revanced_hide_subscriptions_button"),
|
||||||
SwitchPreference("revanced_switch_create_with_notifications_button"),
|
SwitchPreference("revanced_switch_create_with_notifications_button"),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,14 +84,14 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
if (!it.resolve(
|
if (!it.resolve(
|
||||||
context,
|
context,
|
||||||
initializeButtonsResult.mutableMethod,
|
initializeButtonsResult.mutableMethod,
|
||||||
initializeButtonsResult.mutableClass
|
initializeButtonsResult.mutableClass,
|
||||||
)
|
)
|
||||||
)
|
) {
|
||||||
throw it.exception
|
throw it.exception
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.map { it.result!!.scanResult.patternScanResult!! }
|
.map { it.result!!.scanResult.patternScanResult!! }
|
||||||
|
|
||||||
|
|
||||||
val enumScanResult = fingerprintResults[0]
|
val enumScanResult = fingerprintResults[0]
|
||||||
val buttonViewResult = fingerprintResults[1]
|
val buttonViewResult = fingerprintResults[1]
|
||||||
|
|
||||||
|
@ -101,14 +103,14 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val enumHook = "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, " +
|
val enumHook = "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, " +
|
||||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->lastNavigationButton:Ljava/lang/Enum;"
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->lastNavigationButton:Ljava/lang/Enum;"
|
||||||
val buttonHook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
val buttonHook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
||||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideButton(Landroid/view/View;)V"
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideButton(Landroid/view/View;)V"
|
||||||
|
|
||||||
// Inject bottom to top to not mess up the indices
|
// Inject bottom to top to not mess up the indices
|
||||||
mapOf(
|
mapOf(
|
||||||
buttonHook to buttonHookInsertIndex,
|
buttonHook to buttonHookInsertIndex,
|
||||||
enumHook to enumHookInsertIndex
|
enumHook to enumHookInsertIndex,
|
||||||
).forEach { (hook, insertIndex) ->
|
).forEach { (hook, insertIndex) ->
|
||||||
initializeButtonsResult.mutableMethod.injectHook(hook, insertIndex)
|
initializeButtonsResult.mutableMethod.injectHook(hook, insertIndex)
|
||||||
}
|
}
|
||||||
|
@ -131,7 +133,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
"""
|
"""
|
||||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->switchCreateWithNotificationButton()Z
|
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->switchCreateWithNotificationButton()Z
|
||||||
move-result v$conditionRegister
|
move-result v$conditionRegister
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} ?: throw AddCreateButtonViewFingerprint.exception
|
} ?: throw AddCreateButtonViewFingerprint.exception
|
||||||
|
@ -141,8 +143,9 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
*/
|
*/
|
||||||
|
|
||||||
InitializeButtonsFingerprint.result!!.let {
|
InitializeButtonsFingerprint.result!!.let {
|
||||||
if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass))
|
if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass)) {
|
||||||
throw PivotBarCreateButtonViewFingerprint.exception
|
throw PivotBarCreateButtonViewFingerprint.exception
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PivotBarCreateButtonViewFingerprint.result!!.apply {
|
PivotBarCreateButtonViewFingerprint.result!!.apply {
|
||||||
|
@ -152,7 +155,7 @@ object NavigationButtonsPatch : BytecodePatch(
|
||||||
* Inject hooks
|
* Inject hooks
|
||||||
*/
|
*/
|
||||||
val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " +
|
||||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V"
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V"
|
||||||
|
|
||||||
mutableMethod.injectHook(hook, insertIndex)
|
mutableMethod.injectHook(hook, insertIndex)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,9 @@ object HidePlayerButtonsPatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_player_buttons"))
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_player_buttons")
|
||||||
|
)
|
||||||
|
|
||||||
PlayerControlsVisibilityModelFingerprint.result?.apply {
|
PlayerControlsVisibilityModelFingerprint.result?.apply {
|
||||||
val callIndex = scanResult.patternScanResult!!.endIndex
|
val callIndex = scanResult.patternScanResult!!.endIndex
|
||||||
|
|
|
@ -21,7 +21,9 @@ internal object AlbumCardsResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_album_cards"))
|
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_album_cards")
|
||||||
|
)
|
||||||
|
|
||||||
albumCardId = ResourceMappingPatch.resourceMappings.single {
|
albumCardId = ResourceMappingPatch.resourceMappings.single {
|
||||||
it.type == "layout" && it.name == "album_card"
|
it.type == "layout" && it.name == "album_card"
|
||||||
|
|
|
@ -21,7 +21,9 @@ internal object BreakingNewsResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_breaking_news"))
|
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_breaking_news")
|
||||||
|
)
|
||||||
|
|
||||||
horizontalCardListId = ResourceMappingPatch.resourceMappings.single {
|
horizontalCardListId = ResourceMappingPatch.resourceMappings.single {
|
||||||
it.type == "layout" && it.name == "horizontal_card_list"
|
it.type == "layout" && it.name == "horizontal_card_list"
|
||||||
|
|
|
@ -47,9 +47,9 @@ object CommentsPatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
"revanced_comments_preference_screen",
|
"revanced_comments_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_hide_comments_section"),
|
SwitchPreference("revanced_hide_comments_section"),
|
||||||
SwitchPreference("revanced_hide_preview_comment")
|
SwitchPreference("revanced_hide_preview_comment")
|
||||||
|
|
|
@ -21,7 +21,9 @@ internal object CrowdfundingBoxResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_crowdfunding_box"))
|
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_crowdfunding_box")
|
||||||
|
)
|
||||||
|
|
||||||
crowdfundingBoxId = ResourceMappingPatch.resourceMappings.single {
|
crowdfundingBoxId = ResourceMappingPatch.resourceMappings.single {
|
||||||
it.type == "layout" && it.name == "donation_companion"
|
it.type == "layout" && it.name == "donation_companion"
|
||||||
|
|
|
@ -23,7 +23,9 @@ internal object HideEndscreenCardsResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_endscreen_cards"))
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_endscreen_cards")
|
||||||
|
)
|
||||||
|
|
||||||
fun findEndscreenResourceId(name: String) = ResourceMappingPatch.resourceMappings.single {
|
fun findEndscreenResourceId(name: String) = ResourceMappingPatch.resourceMappings.single {
|
||||||
it.type == "layout" && it.name == "endscreen_element_layout_$name"
|
it.type == "layout" && it.name == "endscreen_element_layout_$name"
|
||||||
|
|
|
@ -18,9 +18,9 @@ internal object HideFilterBarResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||||
PreferenceScreen(
|
PreferenceScreen(
|
||||||
key = "revanced_hide_filter_bar_preference",
|
key = "revanced_hide_filter_bar_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_hide_filter_bar_feed_in_feed"),
|
SwitchPreference("revanced_hide_filter_bar_feed_in_feed"),
|
||||||
SwitchPreference("revanced_hide_filter_bar_feed_in_search"),
|
SwitchPreference("revanced_hide_filter_bar_feed_in_search"),
|
||||||
|
|
|
@ -22,7 +22,9 @@ internal object HideFloatingMicrophoneButtonResourcePatch : ResourcePatch() {
|
||||||
override fun execute(context: ResourceContext) {
|
override fun execute(context: ResourceContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_floating_microphone_button"))
|
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_floating_microphone_button")
|
||||||
|
)
|
||||||
|
|
||||||
fabButtonId = ResourceMappingPatch.resourceMappings.find { it.type == "id" && it.name == "fab" }?.id
|
fabButtonId = ResourceMappingPatch.resourceMappings.find { it.type == "id" && it.name == "fab" }?.id
|
||||||
?: throw PatchException("Can not find required fab button resource id")
|
?: throw PatchException("Can not find required fab button resource id")
|
||||||
|
|
|
@ -45,7 +45,7 @@ object DisableFullscreenAmbientModePatch : BytecodePatch(
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
SwitchPreference("revanced_disable_fullscreen_ambient_mode")
|
SwitchPreference("revanced_disable_fullscreen_ambient_mode")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
|
||||||
|
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
|
||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint
|
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint
|
||||||
|
@ -19,7 +21,6 @@ import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverl
|
||||||
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint
|
import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint
|
||||||
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch.PreferenceScreen
|
|
||||||
import app.revanced.util.exception
|
import app.revanced.util.exception
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
|
@ -31,11 +32,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
dependencies = [
|
dependencies = [
|
||||||
LithoFilterPatch::class,
|
LithoFilterPatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
AddResourcesPatch::class
|
AddResourcesPatch::class,
|
||||||
],
|
],
|
||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube", [
|
"com.google.android.youtube",
|
||||||
|
[
|
||||||
"18.32.39",
|
"18.32.39",
|
||||||
"18.37.36",
|
"18.37.36",
|
||||||
"18.38.44",
|
"18.38.44",
|
||||||
|
@ -48,14 +50,14 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
"19.02.39",
|
"19.02.39",
|
||||||
"19.03.35",
|
"19.03.35",
|
||||||
"19.03.36",
|
"19.03.36",
|
||||||
"19.04.37"
|
"19.04.37",
|
||||||
]
|
],
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object HideLayoutComponentsPatch : BytecodePatch(
|
object HideLayoutComponentsPatch : BytecodePatch(
|
||||||
setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint)
|
setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint),
|
||||||
) {
|
) {
|
||||||
private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR =
|
private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;"
|
"Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;"
|
||||||
|
@ -64,59 +66,68 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||||
private const val CUSTOM_FILTER_CLASS_NAME =
|
private const val CUSTOM_FILTER_CLASS_NAME =
|
||||||
"Lapp/revanced/integrations/youtube/patches/components/CustomFilter;"
|
"Lapp/revanced/integrations/youtube/patches/components/CustomFilter;"
|
||||||
|
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
AddResourcesPatch(this::class)
|
AddResourcesPatch(this::class)
|
||||||
|
|
||||||
PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||||
SwitchPreference("revanced_hide_gray_separator"),
|
|
||||||
SwitchPreference("revanced_hide_join_membership_button"),
|
|
||||||
SwitchPreference("revanced_hide_channel_watermark"),
|
|
||||||
SwitchPreference("revanced_hide_for_you_shelf"),
|
|
||||||
SwitchPreference("revanced_hide_notify_me_button"),
|
|
||||||
SwitchPreference("revanced_hide_timed_reactions"),
|
|
||||||
SwitchPreference("revanced_hide_search_result_recommendations"),
|
|
||||||
SwitchPreference("revanced_hide_search_result_shelf_header"),
|
|
||||||
SwitchPreference("revanced_hide_channel_guidelines"),
|
|
||||||
SwitchPreference("revanced_hide_expandable_chip"),
|
|
||||||
SwitchPreference("revanced_hide_video_quality_menu_footer"),
|
|
||||||
SwitchPreference("revanced_hide_chapters"),
|
|
||||||
SwitchPreference("revanced_hide_community_posts"),
|
|
||||||
SwitchPreference("revanced_hide_compact_banner"),
|
|
||||||
SwitchPreference("revanced_hide_movies_section"),
|
|
||||||
SwitchPreference("revanced_hide_feed_survey"),
|
|
||||||
SwitchPreference("revanced_hide_community_guidelines"),
|
|
||||||
SwitchPreference("revanced_hide_subscribers_community_guidelines"),
|
|
||||||
SwitchPreference("revanced_hide_channel_member_shelf"),
|
|
||||||
SwitchPreference("revanced_hide_emergency_box"),
|
|
||||||
SwitchPreference("revanced_hide_info_panels"),
|
|
||||||
SwitchPreference("revanced_hide_medical_panels"),
|
|
||||||
SwitchPreference("revanced_hide_channel_bar"),
|
SwitchPreference("revanced_hide_channel_bar"),
|
||||||
SwitchPreference("revanced_hide_quick_actions"),
|
SwitchPreference("revanced_hide_channel_guidelines"),
|
||||||
SwitchPreference("revanced_hide_related_videos"),
|
SwitchPreference("revanced_hide_channel_member_shelf"),
|
||||||
SwitchPreference("revanced_hide_image_shelf"),
|
SwitchPreference("revanced_hide_channel_watermark"),
|
||||||
SwitchPreference("revanced_hide_latest_posts_ads"),
|
|
||||||
SwitchPreference("revanced_hide_mix_playlists"),
|
|
||||||
SwitchPreference("revanced_hide_artist_cards"),
|
|
||||||
SwitchPreference("revanced_hide_chips_shelf"),
|
SwitchPreference("revanced_hide_chips_shelf"),
|
||||||
app.revanced.patches.shared.misc.settings.preference.PreferenceScreen(
|
SwitchPreference("revanced_hide_community_guidelines"),
|
||||||
"revanced_hide_description_components_preference_screen",
|
PreferenceScreen(
|
||||||
|
key = "revanced_hide_description_components_screen",
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
|
SwitchPreference("revanced_hide_chapters"),
|
||||||
SwitchPreference("revanced_hide_info_cards_section"),
|
SwitchPreference("revanced_hide_info_cards_section"),
|
||||||
SwitchPreference("revanced_hide_game_section"),
|
SwitchPreference("revanced_hide_game_section"),
|
||||||
SwitchPreference("revanced_hide_music_section"),
|
SwitchPreference("revanced_hide_music_section"),
|
||||||
SwitchPreference("revanced_hide_podcast_section"),
|
SwitchPreference("revanced_hide_podcast_section"),
|
||||||
SwitchPreference("revanced_hide_transcript_section"),
|
SwitchPreference("revanced_hide_transcript_section"),
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
app.revanced.patches.shared.misc.settings.preference.PreferenceScreen(
|
SwitchPreference("revanced_hide_emergency_box"),
|
||||||
"revanced_custom_filter_preference_screen",
|
SwitchPreference("revanced_hide_expandable_chip"),
|
||||||
|
SwitchPreference("revanced_hide_info_panels"),
|
||||||
|
SwitchPreference("revanced_hide_medical_panels"),
|
||||||
|
SwitchPreference("revanced_hide_quick_actions"),
|
||||||
|
SwitchPreference("revanced_hide_related_videos"),
|
||||||
|
SwitchPreference("revanced_hide_subscribers_community_guidelines"),
|
||||||
|
SwitchPreference("revanced_hide_timed_reactions"),
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingsPatch.PreferenceScreen.FEED.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_artist_cards"),
|
||||||
|
SwitchPreference("revanced_hide_community_posts"),
|
||||||
|
SwitchPreference("revanced_hide_compact_banner"),
|
||||||
|
SwitchPreference("revanced_hide_feed_survey"),
|
||||||
|
SwitchPreference("revanced_hide_for_you_shelf"),
|
||||||
|
SwitchPreference("revanced_hide_image_shelf"),
|
||||||
|
SwitchPreference("revanced_hide_join_membership_button"),
|
||||||
|
SwitchPreference("revanced_hide_latest_posts_ads"),
|
||||||
|
SwitchPreference("revanced_hide_mix_playlists"),
|
||||||
|
SwitchPreference("revanced_hide_movies_section"),
|
||||||
|
SwitchPreference("revanced_hide_notify_me_button"),
|
||||||
|
SwitchPreference("revanced_hide_search_result_recommendations"),
|
||||||
|
SwitchPreference("revanced_hide_search_result_shelf_header"),
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_gray_separator"),
|
||||||
|
PreferenceScreen(
|
||||||
|
key = "revanced_custom_filter_screen",
|
||||||
|
sorting = Sorting.UNSORTED,
|
||||||
preferences = setOf(
|
preferences = setOf(
|
||||||
SwitchPreference("revanced_custom_filter"),
|
SwitchPreference("revanced_custom_filter"),
|
||||||
// TODO: This should be a dynamic ListPreference, which does not exist yet
|
// TODO: This should be a dynamic ListPreference, which does not exist yet
|
||||||
TextPreference("revanced_custom_filter_strings", inputType = InputType.TEXT_MULTI_LINE)
|
TextPreference("revanced_custom_filter_strings", inputType = InputType.TEXT_MULTI_LINE),
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
|
||||||
|
SwitchPreference("revanced_hide_video_quality_menu_footer"),
|
||||||
)
|
)
|
||||||
|
|
||||||
LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
|
LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR)
|
||||||
|
@ -136,14 +147,15 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||||
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD
|
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
consumeByteBufferIndex, """
|
consumeByteBufferIndex,
|
||||||
|
"""
|
||||||
invoke-static {v$conversionContextRegister, v$byteBufferRegister}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
|
invoke-static {v$conversionContextRegister, v$byteBufferRegister}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
|
||||||
move-result v0 # Conveniently same register happens to be free.
|
move-result v0 # Conveniently same register happens to be free.
|
||||||
if-nez v0, :return_empty_component
|
if-nez v0, :return_empty_component
|
||||||
""", ExternalLabel("return_empty_component", returnEmptyComponentInstruction)
|
""",
|
||||||
|
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
} ?: throw ParseElementFromBufferFingerprint.exception
|
} ?: throw ParseElementFromBufferFingerprint.exception
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
@ -157,10 +169,11 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
||||||
|
|
||||||
removeInstruction(index)
|
removeInstruction(index)
|
||||||
addInstructions(
|
addInstructions(
|
||||||
index, """
|
index,
|
||||||
|
"""
|
||||||
invoke-static {}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->showWatermark()Z
|
invoke-static {}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->showWatermark()Z
|
||||||
move-result p2
|
move-result p2
|
||||||
"""
|
""",
|
||||||
)
|
)
|
||||||
} ?: throw ShowWatermarkFingerprint.exception
|
} ?: throw ShowWatermarkFingerprint.exception
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue