mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-31 22:51:03 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fdfce5b2a | ||
|
|
1616e42a4c | ||
|
|
e85c30c9c2 | ||
|
|
887a916c1a | ||
|
|
903c01b765 | ||
|
|
a8940d8cd0 | ||
|
|
9b0e6b5ed8 | ||
|
|
c3208ff2d1 | ||
|
|
0e3c705dc9 | ||
|
|
d733981342 | ||
|
|
cc59f47f4c |
61
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
61
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
@@ -1,61 +0,0 @@
|
|||||||
name: 🐞 Bug report
|
|
||||||
description: Report a very clearly broken issue.
|
|
||||||
title: 'bug: <title>'
|
|
||||||
labels: [bug]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
# ReVanced bug report
|
|
||||||
|
|
||||||
Important to note that your issue may have already been reported before. Please check for existing issues [here](https://github.com/revanced/revanced-patches/labels/bug).
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Type
|
|
||||||
options:
|
|
||||||
- Error while patching
|
|
||||||
- Error at runtime
|
|
||||||
- Cosmetic
|
|
||||||
- Other
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Bug description
|
|
||||||
description: How did you find the bug? Any additional details that might help?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Steps to reproduce
|
|
||||||
description: Add the steps to reproduce this bug including your environment.
|
|
||||||
placeholder: Step 1. Download some files. Step 2. ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Relevant log output
|
|
||||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
|
||||||
render: shell
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Screenshots or videos
|
|
||||||
description: Add screenshots or videos that show the bug here.
|
|
||||||
placeholder: Drag and drop the screenshots/videos into this box.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Solution
|
|
||||||
description: If applicable, add a possible solution.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add additional context here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +0,0 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: 📃 Documentation
|
|
||||||
url: https://github.com/revanced/revanced-documentation/
|
|
||||||
about: Don't know how or where to start? Check out our documentation!
|
|
||||||
- name: 🗨 Discussions
|
|
||||||
url: https://github.com/revanced/revanced-suggestions/discussions
|
|
||||||
about: Got something you think should change or be added? Search for or start a new discussion!
|
|
||||||
46
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
46
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
@@ -1,46 +0,0 @@
|
|||||||
name: ⭐ Feature request
|
|
||||||
description: Create a detailed feature request.
|
|
||||||
title: 'feat: <title>'
|
|
||||||
labels: [feature-request]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
# ReVanced feature request
|
|
||||||
|
|
||||||
Do not submit requests for patches here. Please submit them [here](https://github.com/orgs/revanced/discussions/categories/patches) instead.
|
|
||||||
Important to note that your feature request may have already been made before. Please check for existing feature requests [here](https://github.com/revanced/revanced-patches/labels/feature-request).
|
|
||||||
|
|
||||||
- type: dropdown
|
|
||||||
attributes:
|
|
||||||
label: Type
|
|
||||||
options:
|
|
||||||
- Functionality
|
|
||||||
- Cosmetic
|
|
||||||
- Other
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Issue
|
|
||||||
description: What is the current problem. Why does it require a feature request?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Feature
|
|
||||||
description: Describe your feature in detail. How does it solve the issue?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Motivation
|
|
||||||
description: Why should your feature should be considered?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add additional context here.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
19
.github/workflows/release.yml
vendored
19
.github/workflows/release.yml
vendored
@@ -12,7 +12,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -24,14 +24,29 @@ jobs:
|
|||||||
java-version: '17'
|
java-version: '17'
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
cache: gradle
|
cache: gradle
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: "lts/*"
|
||||||
- name: Setup Android SDK
|
- name: Setup Android SDK
|
||||||
uses: android-actions/setup-android@v2
|
uses: android-actions/setup-android@v2
|
||||||
|
- name: Make gradlew executable
|
||||||
|
run: chmod +x gradlew
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew build clean generateMeta
|
run: ./gradlew build
|
||||||
- name: Install Android build-tools
|
- name: Install Android build-tools
|
||||||
run: sdkmanager "build-tools;32.0.0"
|
run: sdkmanager "build-tools;32.0.0"
|
||||||
|
- name: Generate Patches DEX
|
||||||
|
run: |
|
||||||
|
mkdir -p bin
|
||||||
|
fn=$(find build/libs -maxdepth 1 | grep -P "[\d]+\.jar")
|
||||||
|
out=bin/$(basename "$fn" | sed 's/jar/dex/g')
|
||||||
|
$ANDROID_HOME/build-tools/32.0.0/d8 $fn
|
||||||
|
mv *.dex $out
|
||||||
|
- name: Clean build
|
||||||
|
run: ./gradlew clean
|
||||||
- name: Setup semantic-release
|
- name: Setup semantic-release
|
||||||
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
||||||
- name: Release
|
- name: Release
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -114,7 +114,4 @@ gradle-app.setting
|
|||||||
# gradle/wrapper/gradle-wrapper.properties
|
# gradle/wrapper/gradle-wrapper.properties
|
||||||
|
|
||||||
# Potentially copyrighted test APK
|
# Potentially copyrighted test APK
|
||||||
*.apk
|
*.apk
|
||||||
|
|
||||||
# Ignore vscode config
|
|
||||||
.vscode/
|
|
||||||
1
.idea/.gitignore
generated
vendored
1
.idea/.gitignore
generated
vendored
@@ -6,4 +6,3 @@
|
|||||||
/dataSources.local.xml
|
/dataSources.local.xml
|
||||||
# Editor-based HTTP Client requests
|
# Editor-based HTTP Client requests
|
||||||
/httpRequests/
|
/httpRequests/
|
||||||
/kotlinc.xml
|
|
||||||
|
|||||||
13
.releaserc
13
.releaserc
@@ -7,22 +7,15 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
["@semantic-release/commit-analyzer", {
|
"@semantic-release/commit-analyzer",
|
||||||
"releaseRules": [
|
|
||||||
{"type": "build", "release": "patch"}
|
|
||||||
]
|
|
||||||
}],
|
|
||||||
"@semantic-release/release-notes-generator",
|
"@semantic-release/release-notes-generator",
|
||||||
"@semantic-release/changelog",
|
"@semantic-release/changelog",
|
||||||
"gradle-semantic-release-plugin",
|
|
||||||
[
|
[
|
||||||
"@semantic-release/git",
|
"@semantic-release/git",
|
||||||
{
|
{
|
||||||
"assets": [
|
"assets": [
|
||||||
"README.md",
|
|
||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
"gradle.properties",
|
"gradle.properties"
|
||||||
"patches.json"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -34,7 +27,7 @@
|
|||||||
"path": "build/libs/*.jar"
|
"path": "build/libs/*.jar"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "patches.json"
|
"path": "bin/*.dex"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1129
CHANGELOG.md
1129
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,72 +0,0 @@
|
|||||||
## 🧩 Patches
|
|
||||||
|
|
||||||
The official Patch bundle provided by ReVanced and the community.
|
|
||||||
|
|
||||||
> Looking for the JSON variant of this? [Click here](patches.json).
|
|
||||||
|
|
||||||
{{ table }}
|
|
||||||
|
|
||||||
## 📝 JSON Format
|
|
||||||
|
|
||||||
This section explains the JSON format for the [patches.json](patches.json) file.
|
|
||||||
|
|
||||||
The file contains an array of objects, each object representing a patch. The object contains the following properties:
|
|
||||||
|
|
||||||
| key | description |
|
|
||||||
|-------------------------------|------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| `name` | The name of the patch. |
|
|
||||||
| `description` | The description of the patch. |
|
|
||||||
| `version` | The version of the patch. |
|
|
||||||
| `excluded` | Whether a patch is excluded by default. If `true`, the patch must never be included by default. |
|
|
||||||
| `dependencies` | An array of dependencies, which are patch names. |
|
|
||||||
| `compatiblePackages` | An array of packages compatible with this patch. |
|
|
||||||
| `compatiblePackages.name` | The name of the package. |
|
|
||||||
| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. |
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "remember-video-quality",
|
|
||||||
"description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"excluded": false,
|
|
||||||
"dependencies": [
|
|
||||||
"integrations",
|
|
||||||
"video-id-hook"
|
|
||||||
],
|
|
||||||
"compatiblePackages": [
|
|
||||||
{
|
|
||||||
"name": "com.google.android.youtube",
|
|
||||||
"versions": [
|
|
||||||
"17.22.36",
|
|
||||||
"17.24.35",
|
|
||||||
"17.26.35",
|
|
||||||
"17.27.39",
|
|
||||||
"17.28.34",
|
|
||||||
"17.29.34",
|
|
||||||
"17.32.35"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "client-spoof",
|
|
||||||
"description": "Spoofs the YouTube or Vanced client to prevent playback issues.",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"excluded": false,
|
|
||||||
"dependencies": [],
|
|
||||||
"compatiblePackages": [
|
|
||||||
{
|
|
||||||
"name": "com.google.android.youtube",
|
|
||||||
"versions": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "com.vanced.android.youtube",
|
|
||||||
"versions": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
172
README.md
172
README.md
@@ -1,170 +1,2 @@
|
|||||||
## 🧩 Patches
|
# revanced-patches
|
||||||
|
Repo for all ReVanced patches
|
||||||
The official Patch bundle provided by ReVanced and the community.
|
|
||||||
|
|
||||||
> Looking for the JSON variant of this? [Click here](patches.json).
|
|
||||||
|
|
||||||
### 📦 `com.twitter.android`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `timeline-ads` | Removes ads from the Twitter timeline. | all |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 📦 `com.reddit.frontpage`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `premium-icon-reddit` | Unlocking Premium Icons in reddit app. | all |
|
|
||||||
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | all |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 📦 `com.garzotto.pflotsh.ecmwf_a`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `pflotsh-ecmwf-subscription-unlock` | Unlocks all subscription features. | 3.5.4 |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 📦 `com.google.android.apps.youtube.music`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `minimized-playback-music` | Enables minimized playback on Kids music. | 5.22.54 |
|
|
||||||
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.22.54 |
|
|
||||||
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.22.54 |
|
|
||||||
| `compact-header` | Hides the music category bar at the top of the homepage. | 5.22.54 |
|
|
||||||
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.22.54 |
|
|
||||||
| `background-play` | Enables playing music in the background. | 5.22.54 |
|
|
||||||
| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | 5.22.54 |
|
|
||||||
| `music-video-ads` | Removes ads in the music player. | 5.22.54 |
|
|
||||||
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.22.54 |
|
|
||||||
| `exclusive-audio-playback` | Enables the option to play music without video. | 5.22.54 |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 📦 `de.dwd.warnapp`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 📦 `com.ss.android.ugc.trill`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `tiktok-download` | Remove restrictions on downloads video. | all |
|
|
||||||
| `tiktok-seekbar` | Show progress bar for all video. | all |
|
|
||||||
| `tiktok-ads` | Removes ads from TikTok. | all |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### 📦 `com.google.android.youtube`
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `swipe-controls` | Adds volume and brightness swipe controls. | 17.33.42 |
|
|
||||||
| `downloads` | Enables downloading music and videos from YouTube. | 17.33.42 |
|
|
||||||
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.33.42 |
|
|
||||||
| `amoled` | Enables pure black theme. | all |
|
|
||||||
| `disable-create-button` | Hides the create button in the navigation bar. | 17.33.42 |
|
|
||||||
| `hide-cast-button` | Hides the cast button in the video player. | all |
|
|
||||||
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 17.33.42 |
|
|
||||||
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.33.42 |
|
|
||||||
| `premium-heading` | Shows premium branding on the home screen. | all |
|
|
||||||
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
|
|
||||||
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 17.33.42 |
|
|
||||||
| `old-quality-layout` | Enables the original quality flyout menu. | 17.33.42 |
|
|
||||||
| `theme` | Enables a custom theme. | all |
|
|
||||||
| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 17.33.42 |
|
|
||||||
| `hide-watermark` | Hides creator's watermarks on videos. | 17.33.42 |
|
|
||||||
| `sponsorblock` | Integrate SponsorBlock. | 17.33.42 |
|
|
||||||
| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 17.33.42 |
|
|
||||||
| `tablet-mini-player` | Enables the tablet mini player layout. | 17.33.42 |
|
|
||||||
| `minimized-playback` | Enables minimized and background playback. | 17.33.42 |
|
|
||||||
| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all |
|
|
||||||
| `custom-video-buffer` | Lets you change the buffers of videos. | 17.33.42 |
|
|
||||||
| `always-autorepeat` | Always repeats the playing video again. | 17.33.42 |
|
|
||||||
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 17.33.42 |
|
|
||||||
| `settings` | Adds settings for ReVanced to YouTube. | all |
|
|
||||||
| `enable-debugging` | Enables app debugging by patching the manifest file. | all |
|
|
||||||
| `custom-playback-speed` | Adds more video playback speed options. | 17.33.42 |
|
|
||||||
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.33.42 |
|
|
||||||
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 17.33.42 |
|
|
||||||
| `video-ads` | Removes ads in the video player. | 17.33.42 |
|
|
||||||
| `general-ads` | Removes general ads. | 17.33.42 |
|
|
||||||
| `hide-infocard-suggestions` | Hides infocards in videos. | 17.33.42 |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 📝 JSON Format
|
|
||||||
|
|
||||||
This section explains the JSON format for the [patches.json](patches.json) file.
|
|
||||||
|
|
||||||
The file contains an array of objects, each object representing a patch. The object contains the following properties:
|
|
||||||
|
|
||||||
| key | description |
|
|
||||||
|-------------------------------|------------------------------------------------------------------------------------------------------------------|
|
|
||||||
| `name` | The name of the patch. |
|
|
||||||
| `description` | The description of the patch. |
|
|
||||||
| `version` | The version of the patch. |
|
|
||||||
| `excluded` | Whether a patch is excluded by default. If `true`, the patch must never be included by default. |
|
|
||||||
| `dependencies` | An array of dependencies, which are patch names. |
|
|
||||||
| `compatiblePackages` | An array of packages compatible with this patch. |
|
|
||||||
| `compatiblePackages.name` | The name of the package. |
|
|
||||||
| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. |
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": "remember-video-quality",
|
|
||||||
"description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"excluded": false,
|
|
||||||
"dependencies": [
|
|
||||||
"integrations",
|
|
||||||
"video-id-hook"
|
|
||||||
],
|
|
||||||
"compatiblePackages": [
|
|
||||||
{
|
|
||||||
"name": "com.google.android.youtube",
|
|
||||||
"versions": [
|
|
||||||
"17.22.36",
|
|
||||||
"17.24.35",
|
|
||||||
"17.26.35",
|
|
||||||
"17.27.39",
|
|
||||||
"17.28.34",
|
|
||||||
"17.29.34",
|
|
||||||
"17.32.35"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "client-spoof",
|
|
||||||
"description": "Spoofs the YouTube or Vanced client to prevent playback issues.",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"excluded": false,
|
|
||||||
"dependencies": [],
|
|
||||||
"compatiblePackages": [
|
|
||||||
{
|
|
||||||
"name": "com.google.android.youtube",
|
|
||||||
"versions": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "com.vanced.android.youtube",
|
|
||||||
"versions": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -4,64 +4,19 @@ plugins {
|
|||||||
|
|
||||||
group = "app.revanced"
|
group = "app.revanced"
|
||||||
|
|
||||||
val githubUsername: String = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
|
|
||||||
val githubPassword: String = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
mavenLocal()
|
|
||||||
maven {
|
maven {
|
||||||
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
|
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
|
||||||
credentials {
|
credentials {
|
||||||
username = githubUsername
|
username = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
|
||||||
password = githubPassword
|
password = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("app.revanced:revanced-patcher:4.2.2")
|
implementation(kotlin("stdlib"))
|
||||||
implementation("app.revanced:multidexlib2:2.5.2.r2")
|
|
||||||
|
|
||||||
// Required for meta
|
implementation("app.revanced:revanced-patcher:1.1.0")
|
||||||
implementation("com.google.code.gson:gson:2.9.1")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tasks {
|
|
||||||
register<DefaultTask>("generateBundle") {
|
|
||||||
description = "Generate dex files from build and bundle them in the jar file"
|
|
||||||
dependsOn(build)
|
|
||||||
|
|
||||||
doLast {
|
|
||||||
val androidHome = System.getenv("ANDROID_HOME") ?: throw GradleException("ANDROID_HOME not found")
|
|
||||||
val d8 = "${androidHome}/build-tools/32.0.0/d8"
|
|
||||||
val input = configurations.archives.get().allArtifacts.files.files.first().absolutePath
|
|
||||||
val work = File("${buildDir}/libs")
|
|
||||||
|
|
||||||
exec {
|
|
||||||
workingDir = work
|
|
||||||
commandLine = listOf(d8, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
exec {
|
|
||||||
workingDir = work
|
|
||||||
commandLine = listOf("zip", "-u", input, "classes.dex")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
register<JavaExec>("generateMeta") {
|
|
||||||
description = "Generate metadata for this bundle"
|
|
||||||
dependsOn(build)
|
|
||||||
|
|
||||||
classpath = sourceSets["main"].runtimeClasspath
|
|
||||||
mainClass.set("app.revanced.meta.Meta")
|
|
||||||
}
|
|
||||||
// Dummy task to fix the Gradle semantic-release plugin.
|
|
||||||
// Remove this if you forked it to support building only.
|
|
||||||
// Tracking issue: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
|
||||||
register<DefaultTask>("publish") {
|
|
||||||
group = "publish"
|
|
||||||
description = "Dummy task"
|
|
||||||
dependsOn(named("generateBundle"), named("generateMeta"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 2.51.2
|
version = 1.2.1
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,195 +1,19 @@
|
|||||||
package app.revanced.extensions
|
package app.revanced.extensions
|
||||||
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.data.impl.ResourceData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patcher.util.smali.toInstruction
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction11n
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
|
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
|
||||||
import org.w3c.dom.Node
|
import org.w3c.dom.Node
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
// TODO: this method does not make sense here
|
|
||||||
internal fun MutableMethodImplementation.injectHideCall(
|
internal fun MutableMethodImplementation.injectHideCall(
|
||||||
index: Int,
|
index: Int,
|
||||||
register: Int
|
register: Int
|
||||||
) {
|
) {
|
||||||
this.addInstruction(
|
this.addInstruction(
|
||||||
index,
|
index,
|
||||||
"invoke-static { v$register }, Lapp/revanced/integrations/patches/HideHomeAdsPatch;->HideHomeAds(Landroid/view/View;)V".toInstruction()
|
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->HideView(Landroid/view/View;)V".toInstruction()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* traverse the class hierarchy starting from the given root class
|
|
||||||
*
|
|
||||||
* @param targetClass the class to start traversing the class hierarchy from
|
|
||||||
* @param callback function that is called for every class in the hierarchy
|
|
||||||
*/
|
|
||||||
fun BytecodeData.traverseClassHierarchy(targetClass: MutableClass, callback: MutableClass.() -> Unit) {
|
|
||||||
callback(targetClass)
|
|
||||||
this.findClass(targetClass.superclass ?: return)?.resolve()?.let {
|
|
||||||
traverseClassHierarchy(it, callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* apply a transform to all methods of the class
|
|
||||||
*
|
|
||||||
* @param transform the transformation function. original method goes in, transformed method goes out
|
|
||||||
*/
|
|
||||||
fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) {
|
|
||||||
val transformedMethods = methods.map { it.transform() }
|
|
||||||
methods.clear()
|
|
||||||
methods.addAll(transformedMethods)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert an event hook at the top of the method. If the hook returns true, the event is consumed and the method will return with true
|
|
||||||
*
|
|
||||||
* the hook method MUST return a boolean and MUST take two parameters, like so:
|
|
||||||
* fun hook(thisRef: Object, eventData: Object): Boolean {}
|
|
||||||
*
|
|
||||||
* The final injected code will resemble the following logic:
|
|
||||||
* if( YouHook(this, event) ) { return true; }
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
* @param hookRef reference to the hook method
|
|
||||||
*/
|
|
||||||
internal fun MutableMethod.injectConsumableEventHook(hookRef: ImmutableMethodReference) {
|
|
||||||
val isStaticMethod = AccessFlags.STATIC.isSet(this.accessFlags)
|
|
||||||
this.implementation?.let { impl ->
|
|
||||||
// create label to index 0 to continue to the normal program flow
|
|
||||||
val lblContinueNormalFlow = impl.newLabelForIndex(0)
|
|
||||||
|
|
||||||
// define registers
|
|
||||||
/** V0 */
|
|
||||||
val regV0 = 0
|
|
||||||
|
|
||||||
/** this */
|
|
||||||
val regP0 = impl.registerCount - this.parameters.size - (if (isStaticMethod) 0 else 1)
|
|
||||||
|
|
||||||
/** motionEvent */
|
|
||||||
val regP1 = regP0 + 1
|
|
||||||
|
|
||||||
// insert instructions at the start of the method:
|
|
||||||
// if( Hook(this, event) ) { return true; }
|
|
||||||
impl.addInstructions(
|
|
||||||
0, listOf(
|
|
||||||
// invoke-static { p0, p1 } <hook>
|
|
||||||
BuilderInstruction35c(
|
|
||||||
Opcode.INVOKE_STATIC,
|
|
||||||
2,
|
|
||||||
regP0,
|
|
||||||
regP1,
|
|
||||||
0, 0, 0,
|
|
||||||
hookRef
|
|
||||||
),
|
|
||||||
|
|
||||||
// move-result v0
|
|
||||||
BuilderInstruction11x(
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
regV0
|
|
||||||
),
|
|
||||||
|
|
||||||
// if-eqz v0, :continue_normal_flow
|
|
||||||
BuilderInstruction21t(
|
|
||||||
Opcode.IF_EQZ,
|
|
||||||
regV0,
|
|
||||||
lblContinueNormalFlow
|
|
||||||
),
|
|
||||||
|
|
||||||
// const/4 v0, 0x1
|
|
||||||
BuilderInstruction11n(
|
|
||||||
Opcode.CONST_4,
|
|
||||||
regV0,
|
|
||||||
0x1
|
|
||||||
),
|
|
||||||
|
|
||||||
// return v0
|
|
||||||
BuilderInstruction11x(
|
|
||||||
Opcode.RETURN,
|
|
||||||
regV0
|
|
||||||
)
|
|
||||||
|
|
||||||
// :continue_normal_flow
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inject resources into the patched app
|
|
||||||
*
|
|
||||||
* @param classLoader classloader to use for loading the resources
|
|
||||||
* @param patchDirectoryPath path to the files. this will be the directory you created under the 'resources' source folder
|
|
||||||
* @param resourceType the resource type, for example 'drawable'. this has to match both the source and the target
|
|
||||||
* @param resourceFileNames names of all resources of this type to inject
|
|
||||||
*/
|
|
||||||
fun ResourceData.injectResources(
|
|
||||||
classLoader: ClassLoader,
|
|
||||||
patchDirectoryPath: String,
|
|
||||||
resourceType: String,
|
|
||||||
resourceFileNames: List<String>
|
|
||||||
) {
|
|
||||||
resourceFileNames.forEach { name ->
|
|
||||||
val relativePath = "$resourceType/$name"
|
|
||||||
val sourceRes = classLoader.getResourceAsStream("$patchDirectoryPath/$relativePath")
|
|
||||||
?: throw PatchResultError("could not open resource '$patchDirectoryPath/$relativePath'")
|
|
||||||
|
|
||||||
Files.copy(
|
|
||||||
sourceRes,
|
|
||||||
this["res"].resolve(relativePath).toPath()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* inject strings into the patched app
|
|
||||||
*
|
|
||||||
* @param classLoader classloader to use for loading the resources
|
|
||||||
* @param patchDirectoryPath path to the files. this will be the directory you created under the 'resources' source folder
|
|
||||||
* @param languageIdentifier ISO 639-2 two- letter language code identifier (aka the one android uses for values directory)
|
|
||||||
*/
|
|
||||||
fun ResourceData.injectStrings(
|
|
||||||
classLoader: ClassLoader,
|
|
||||||
patchDirectoryPath: String,
|
|
||||||
languageIdentifier: String? = null,
|
|
||||||
) {
|
|
||||||
val relativePath =
|
|
||||||
if (languageIdentifier.isNullOrBlank()) "values/strings.xml" else "values/strings-$languageIdentifier.xml"
|
|
||||||
|
|
||||||
// open source strings.xml
|
|
||||||
val sourceInputStream = classLoader.getResourceAsStream("$patchDirectoryPath/$relativePath")
|
|
||||||
?: throw PatchResultError("failed to open '$patchDirectoryPath/$relativePath'")
|
|
||||||
xmlEditor[sourceInputStream].use { sourceStringsXml ->
|
|
||||||
val strings = sourceStringsXml.file.getElementsByTagName("resources").item(0).childNodes
|
|
||||||
|
|
||||||
// open target strings.xml
|
|
||||||
xmlEditor["res/$relativePath"].use { targetStringsXml ->
|
|
||||||
val targetFile = targetStringsXml.file
|
|
||||||
val targetRootNode = targetFile.getElementsByTagName("resources").item(0)
|
|
||||||
|
|
||||||
// process all children strings in the source
|
|
||||||
for (i in 0 until strings.length) {
|
|
||||||
// clone the node from source to target
|
|
||||||
val node = strings.item(i).cloneNode(true)
|
|
||||||
targetFile.adoptNode(node)
|
|
||||||
targetRootNode.appendChild(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun Node.doRecursively(action: (Node) -> Unit) {
|
internal fun Node.doRecursively(action: (Node) -> Unit) {
|
||||||
action(this)
|
action(this)
|
||||||
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package app.revanced.meta
|
|
||||||
|
|
||||||
import app.revanced.meta.json.generateJson
|
|
||||||
import app.revanced.meta.readme.generateText
|
|
||||||
import app.revanced.patcher.data.Data
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.util.patch.impl.JarPatchBundle
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
typealias Bundle = List<Class<out Patch<Data>>>
|
|
||||||
|
|
||||||
object Meta {
|
|
||||||
@JvmStatic
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
val patches = accumulatePatches()
|
|
||||||
if (patches.isEmpty()) throw IllegalStateException("No patches found")
|
|
||||||
|
|
||||||
generateText(patches)
|
|
||||||
generateJson(patches)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun accumulatePatches() = JarPatchBundle(
|
|
||||||
File("build/libs/").listFiles()!!.first {
|
|
||||||
it.name.startsWith("revanced-patches-") && it.name.endsWith(".jar")
|
|
||||||
}.absolutePath
|
|
||||||
).loadPatches()
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.meta.json
|
|
||||||
|
|
||||||
import app.revanced.meta.Bundle
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.dependencies
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.description
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.include
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.version
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
private val gson = Gson()
|
|
||||||
|
|
||||||
fun generateJson(bundle: Bundle) {
|
|
||||||
val patches = bundle.map {
|
|
||||||
JsonPatch(
|
|
||||||
it.patchName,
|
|
||||||
it.description ?: "This patch has no description.",
|
|
||||||
it.version ?: "0.0.0",
|
|
||||||
!it.include,
|
|
||||||
it.dependencies?.map { dep ->
|
|
||||||
dep.java.patchName
|
|
||||||
}?.toTypedArray() ?: emptyArray(),
|
|
||||||
it.compatiblePackages?.map { pkg ->
|
|
||||||
CompatiblePackage(pkg.name, pkg.versions)
|
|
||||||
}?.toTypedArray() ?: emptyArray()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val json = File("patches.json")
|
|
||||||
json.writeText(gson.toJson(patches))
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
@file:Suppress("ArrayInDataClass") // We don't need it here.
|
|
||||||
|
|
||||||
package app.revanced.meta.json
|
|
||||||
|
|
||||||
data class JsonPatch(
|
|
||||||
val name: String,
|
|
||||||
val description: String,
|
|
||||||
val version: String,
|
|
||||||
val excluded: Boolean,
|
|
||||||
val dependencies: Array<String>,
|
|
||||||
val compatiblePackages: Array<CompatiblePackage>,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class CompatiblePackage(
|
|
||||||
val name: String,
|
|
||||||
val versions: Array<String>,
|
|
||||||
)
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package app.revanced.meta.readme
|
|
||||||
|
|
||||||
import app.revanced.patcher.data.Data
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
|
|
||||||
internal fun Class<out Patch<Data>>.getLatestVersion() =
|
|
||||||
this.compatiblePackages?.first()?.versions?.map {
|
|
||||||
SemanticVersion.fromString(it)
|
|
||||||
}?.maxWithOrNull(SemanticVersionComparator)
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package app.revanced.meta.readme
|
|
||||||
|
|
||||||
import app.revanced.meta.Bundle
|
|
||||||
import app.revanced.patcher.data.Data
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.description
|
|
||||||
import app.revanced.patcher.extensions.PatchExtensions.patchName
|
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
private const val TABLE_HEADER =
|
|
||||||
"| \uD83D\uDC8A Patch | \uD83D\uDCDC Description | \uD83C\uDFF9 Target Version |\n" + "|:--------:|:--------------:|:-----------------:|"
|
|
||||||
|
|
||||||
private val TABLE_REGEX = Regex("\\{\\{\\s?table\\s?}}")
|
|
||||||
|
|
||||||
fun generateText(bundle: Bundle) {
|
|
||||||
val output = StringBuilder()
|
|
||||||
val packages = mutableMapOf<String, MutableList<Class<out Patch<Data>>>>()
|
|
||||||
|
|
||||||
bundle.map {
|
|
||||||
val packageName = it.compatiblePackages?.first()?.name!!
|
|
||||||
if (!packages.contains(packageName)) {
|
|
||||||
packages[packageName] = mutableListOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
packages[packageName]?.add(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (pkg in packages) {
|
|
||||||
output.appendLine("### \uD83D\uDCE6 `${pkg.key}`")
|
|
||||||
output.appendLine("<details>\n")
|
|
||||||
|
|
||||||
output.appendLine(TABLE_HEADER)
|
|
||||||
pkg.value.forEach { output.appendLine("| `${it.patchName}` | ${it.description} | ${it.getLatestVersion() ?: "all"} |") }
|
|
||||||
|
|
||||||
output.appendLine("</details>\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
val readmeTemplate = Template(File("README-template.md").readText())
|
|
||||||
readmeTemplate.replaceVariable(TABLE_REGEX, output.toString())
|
|
||||||
|
|
||||||
val readme = File("README.md")
|
|
||||||
readme.writeText(readmeTemplate.toString())
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.meta.readme
|
|
||||||
|
|
||||||
data class SemanticVersion(val major: Int, val minor: Int, val patch: Int) {
|
|
||||||
companion object {
|
|
||||||
fun fromString(version: String): SemanticVersion {
|
|
||||||
val parts = version.split(".")
|
|
||||||
if (parts.count() != 3) throw IllegalArgumentException("Invalid semantic version")
|
|
||||||
val versionNumbers = parts.map { it.toInt() }
|
|
||||||
return SemanticVersion(versionNumbers[0], versionNumbers[1], versionNumbers[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = "$major.$minor.$patch"
|
|
||||||
}
|
|
||||||
|
|
||||||
object SemanticVersionComparator : Comparator<SemanticVersion> {
|
|
||||||
override fun compare(a: SemanticVersion, b: SemanticVersion): Int = when {
|
|
||||||
a.major != b.major -> a.major - b.major
|
|
||||||
a.minor != b.minor -> a.minor - b.minor
|
|
||||||
else -> a.patch - b.patch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package app.revanced.meta.readme
|
|
||||||
|
|
||||||
class Template(template: String) {
|
|
||||||
val result = StringBuilder(template)
|
|
||||||
|
|
||||||
fun replaceVariable(regex: Regex, value: String) {
|
|
||||||
val range = regex.find(result)!!.range
|
|
||||||
result.replace(range.first, range.last + 1, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String = result.toString()
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package app.revanced.patches.music.ad.video.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[Package(
|
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class MusicVideoAdsCompatibility
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package app.revanced.patches.music.ad.video.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("show-video-ads-constructor-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Laghd;",
|
|
||||||
"<init>",
|
|
||||||
)
|
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
|
||||||
@MusicVideoAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint(
|
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.NEW_INSTANCE,
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.NEW_INSTANCE,
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.NEW_INSTANCE,
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.IPUT_BOOLEAN,
|
|
||||||
Opcode.RETURN_VOID
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package app.revanced.patches.music.ad.video.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("show-video-ads-method-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Laghd;", "d"
|
|
||||||
)
|
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
|
||||||
@MusicVideoAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ShowMusicVideoAdsFingerprint : MethodFingerprint(
|
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf(
|
|
||||||
Opcode.IPUT_BOOLEAN,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.RETURN_VOID
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package app.revanced.patches.music.ad.video.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility
|
|
||||||
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint
|
|
||||||
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("music-video-ads")
|
|
||||||
@Description("Removes ads in the music player.")
|
|
||||||
@MusicVideoAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class MusicVideoAdsPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
ShowMusicVideoAdsConstructorFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
ShowMusicVideoAdsFingerprint.resolve(data, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef)
|
|
||||||
|
|
||||||
val result = ShowMusicVideoAdsFingerprint.result!!
|
|
||||||
|
|
||||||
result.mutableMethod.addInstructions(
|
|
||||||
result.patternScanResult!!.startIndex, """
|
|
||||||
const/4 p1, 0x0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,10 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
internal annotation class CodecsUnlockCompatibility
|
internal annotation class CodecsUnlockCompatibility
|
||||||
|
|
||||||
|
|||||||
@@ -3,52 +3,41 @@ package app.revanced.patches.music.audio.codecs.patch
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.data.impl.toMethodWalker
|
import app.revanced.patcher.data.implementation.toMethodWalker
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.smali.toInstruction
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
||||||
import app.revanced.patches.music.audio.codecs.fingerprints.AllCodecsReferenceFingerprint
|
import app.revanced.patches.music.audio.codecs.signatures.AllCodecsReferenceSignature
|
||||||
import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprint
|
import app.revanced.patches.music.audio.codecs.signatures.CodecsLockSignature
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("codecs-unlock")
|
@Name("codecs-unlock")
|
||||||
@Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.")
|
@Description("Enables more audio codecs. Usually results in better audio quality but may depend on song and device.")
|
||||||
@CodecsUnlockCompatibility
|
@CodecsUnlockCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class CodecsUnlockPatch : BytecodePatch(
|
class CodecsUnlockPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
CodecsLockFingerprint, AllCodecsReferenceFingerprint
|
CodecsLockSignature, AllCodecsReferenceSignature
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
val codecsLockResult = CodecsLockFingerprint.result!!
|
var result = signatures.first().result!!
|
||||||
|
|
||||||
val implementation = codecsLockResult.mutableMethod.implementation!!
|
val implementation = result.method.implementation!!
|
||||||
|
|
||||||
val scanResultStartIndex = codecsLockResult.patternScanResult!!.startIndex
|
val instructionIndex = result.scanResult.startIndex
|
||||||
val instructionIndex = scanResultStartIndex +
|
|
||||||
if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) {
|
|
||||||
// for 5.16.xx and lower
|
|
||||||
-3
|
|
||||||
} else {
|
|
||||||
// since 5.17.xx
|
|
||||||
-2
|
|
||||||
}
|
|
||||||
|
|
||||||
val allCodecsResult = AllCodecsReferenceFingerprint.result!!
|
result = signatures.last().result!!
|
||||||
val allCodecsMethod =
|
val codecMethod =
|
||||||
data.toMethodWalker(allCodecsResult.method)
|
data.toMethodWalker(result.immutableMethod).nextMethod(result.scanResult.startIndex).getMethod()
|
||||||
.nextMethod(allCodecsResult.patternScanResult!!.startIndex)
|
|
||||||
.getMethod()
|
|
||||||
|
|
||||||
implementation.replaceInstruction(
|
implementation.replaceInstruction(
|
||||||
instructionIndex,
|
instructionIndex,
|
||||||
"invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction()
|
"invoke-static {}, ${codecMethod.definingClass}->${codecMethod.name}()Ljava/util/Set;".toInstruction()
|
||||||
)
|
)
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package app.revanced.patches.music.audio.codecs.fingerprints
|
package app.revanced.patches.music.audio.codecs.signatures
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher. fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("all-codecs-reference-fingerprint")
|
@Name("all-codecs-reference-signature")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Laari;",
|
"Laari;",
|
||||||
"b",
|
"b",
|
||||||
@@ -18,7 +18,7 @@ import org.jf.dexlib2.Opcode
|
|||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
@CodecsUnlockCompatibility
|
@CodecsUnlockCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object AllCodecsReferenceFingerprint : MethodFingerprint(
|
object AllCodecsReferenceSignature : MethodSignature(
|
||||||
"J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
"J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
@@ -1,25 +1,27 @@
|
|||||||
package app.revanced.patches.music.audio.codecs.fingerprints
|
package app.revanced.patches.music.audio.codecs.signatures
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("codec-lock-fingerprint")
|
@Name("codec-lock-signature")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Lacfr;",
|
"Labwj;",
|
||||||
"a",
|
"a",
|
||||||
)
|
)
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
@CodecsUnlockCompatibility
|
@CodecsUnlockCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object CodecsLockFingerprint : MethodFingerprint(
|
object CodecsLockSignature : MethodSignature(
|
||||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf(
|
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L", "L", "L"), listOf(
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT,
|
Opcode.MOVE_RESULT,
|
||||||
@@ -27,13 +29,19 @@ object CodecsLockFingerprint : MethodFingerprint(
|
|||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT,
|
Opcode.MOVE_RESULT,
|
||||||
Opcode.IF_NEZ,
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.SGET,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_INTERFACE,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
Opcode.SGET_OBJECT,
|
Opcode.SGET_OBJECT,
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.INVOKE_STATIC,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CHECK_CAST,
|
||||||
Opcode.INVOKE_INTERFACE,
|
Opcode.INVOKE_INTERFACE,
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.RETURN_OBJECT
|
Opcode.RETURN_OBJECT
|
||||||
),
|
)
|
||||||
strings = listOf("eac3_supported")
|
)
|
||||||
)
|
|
||||||
@@ -5,9 +5,10 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
internal annotation class ExclusiveAudioCompatibility
|
internal annotation class ExclusiveAudioCompatibility
|
||||||
|
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package app.revanced.patches.music.audio.exclusiveaudio.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("audio-only-enabler-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lgmd;",
|
|
||||||
"d"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@ExclusiveAudioCompatibility
|
|
||||||
@Version(
|
|
||||||
"0.0.1"
|
|
||||||
)
|
|
||||||
object AudioOnlyEnablerFingerprint: MethodFingerprint(
|
|
||||||
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.CHECK_CAST,
|
|
||||||
Opcode.IF_NEZ,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
Opcode.GOTO,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
Opcode.RETURN
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -3,33 +3,68 @@ package app.revanced.patches.music.audio.exclusiveaudio.patch
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
||||||
import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AudioOnlyEnablerFingerprint
|
import app.revanced.patches.music.audio.exclusiveaudio.signatures.ExclusiveAudioSignature
|
||||||
import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.ExclusiveAudioFingerprint
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("exclusive-audio-playback")
|
@Name("exclusive-audio-playback")
|
||||||
@Description("Enables the option to play music without video.")
|
@Description("Add the option to play music without video.")
|
||||||
@ExclusiveAudioCompatibility
|
@ExclusiveAudioCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class ExclusiveAudioPatch : BytecodePatch(
|
class ExclusiveAudioPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
AudioOnlyEnablerFingerprint
|
ExclusiveAudioSignature
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
val method = AudioOnlyEnablerFingerprint.result!!.mutableMethod
|
val result = signatures.first().result!!.findParentMethod(@Name("audio-only-enabler-method") @MatchingMethod(
|
||||||
method.replaceInstruction(method.implementation!!.instructions.count() - 1, "const/4 v0, 0x1")
|
"Lgmd;",
|
||||||
method.addInstruction("return v0")
|
"d"
|
||||||
|
) @DirectPatternScanMethod @ExclusiveAudioCompatibility @Version(
|
||||||
|
"0.0.1"
|
||||||
|
) object : MethodSignature(
|
||||||
|
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_INTERFACE,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_INTERFACE,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CHECK_CAST,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.RETURN
|
||||||
|
)
|
||||||
|
) {}) ?: return PatchResultError("Required parent method could not be found.")
|
||||||
|
|
||||||
|
val implementation = result.method.implementation!!
|
||||||
|
implementation.replaceInstruction(
|
||||||
|
implementation.instructions.count() - 1, "const/4 v0, 0x1".toInstruction()
|
||||||
|
)
|
||||||
|
implementation.addInstruction(
|
||||||
|
"return v0".toInstruction()
|
||||||
|
)
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
package app.revanced.patches.music.audio.exclusiveaudio.fingerprints
|
package app.revanced.patches.music.audio.exclusiveaudio.signatures
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("exclusive-audio-fingerprints")
|
@Name("exclusive-audio-signature")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Lgmd;", "c"
|
"Lgmd;", "c"
|
||||||
)
|
)
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
@ExclusiveAudioCompatibility
|
@ExclusiveAudioCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object ExclusiveAudioFingerprint : MethodFingerprint(
|
object ExclusiveAudioSignature : MethodSignature(
|
||||||
"V",
|
"V",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
listOf("L", "Z"),
|
listOf("L", "Z"),
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.compactheader.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[Package(
|
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.21.52", "5.22.54")
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class CompactHeaderCompatibility
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.compactheader.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patches.music.layout.compactheader.annotations.CompactHeaderCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("compact-header-constructor-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Llcz;", "<init>"
|
|
||||||
)
|
|
||||||
@CompactHeaderCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object CompactHeaderConstructorFingerprint : MethodFingerprint(
|
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf(
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.NEW_INSTANCE,
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.CONST,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.INVOKE_STATIC,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.CHECK_CAST
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.compactheader.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patches.music.layout.compactheader.annotations.CompactHeaderCompatibility
|
|
||||||
import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
|
|
||||||
|
|
||||||
@Patch(false)
|
|
||||||
@Name("compact-header")
|
|
||||||
@Description("Hides the music category bar at the top of the homepage.")
|
|
||||||
@CompactHeaderCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class CompactHeaderPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
CompactHeaderConstructorFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
val result = CompactHeaderConstructorFingerprint.result!!
|
|
||||||
val method = result.mutableMethod
|
|
||||||
|
|
||||||
val insertIndex = result.patternScanResult!!.endIndex
|
|
||||||
val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA
|
|
||||||
method.addInstructions(
|
|
||||||
insertIndex, """
|
|
||||||
const/16 v2, 0x8
|
|
||||||
invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.minimizedplayback.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[Package(
|
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class MinimizedPlaybackCompatibility
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patches.music.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("minimized-playback-manager-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Llxw;", "c"
|
|
||||||
)
|
|
||||||
@MinimizedPlaybackCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
|
|
||||||
"V",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
listOf("I", "L", "Z"),
|
|
||||||
listOf(
|
|
||||||
Opcode.IGET,
|
|
||||||
Opcode.IF_NE,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IF_NE,
|
|
||||||
Opcode.IGET_BOOLEAN,
|
|
||||||
Opcode.IF_EQ,
|
|
||||||
Opcode.GOTO,
|
|
||||||
Opcode.RETURN_VOID,
|
|
||||||
Opcode.SGET_OBJECT,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.IF_NE,
|
|
||||||
Opcode.IPUT_BOOLEAN,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.minimizedplayback.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.data.impl.toMethodWalker
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patches.music.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
|
||||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("minimized-playback-music")
|
|
||||||
@Description("Enables minimized playback on Kids music.")
|
|
||||||
@MinimizedPlaybackCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class MinimizedPlaybackPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
MinimizedPlaybackManagerFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions(
|
|
||||||
0, """
|
|
||||||
return-void
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.premium.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[Package(
|
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class HideGetPremiumCompatibility
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.premium.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patches.music.layout.premium.annotations.HideGetPremiumCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("hide-get-premium-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lktn;", "k"
|
|
||||||
)
|
|
||||||
@HideGetPremiumCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object HideGetPremiumFingerprint : MethodFingerprint(
|
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
|
||||||
Opcode.IF_NEZ,
|
|
||||||
Opcode.CONST_16,
|
|
||||||
Opcode.GOTO,
|
|
||||||
Opcode.NOP,
|
|
||||||
Opcode.INVOKE_VIRTUAL
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.premium.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patches.music.layout.premium.annotations.HideGetPremiumCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("hide-get-premium-parent-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lktn;", "k"
|
|
||||||
)
|
|
||||||
@HideGetPremiumCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object HideGetPremiumParentFingerprint : MethodFingerprint(
|
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
|
||||||
Opcode.IGET_BOOLEAN,
|
|
||||||
Opcode.CONST_4,
|
|
||||||
Opcode.IF_EQZ,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.INVOKE_STATIC
|
|
||||||
),
|
|
||||||
listOf("FEmusic_history"),
|
|
||||||
)
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
package app.revanced.patches.music.layout.premium.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patches.music.layout.premium.annotations.HideGetPremiumCompatibility
|
|
||||||
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint
|
|
||||||
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("hide-get-premium")
|
|
||||||
@Description("Removes all \"Get Premium\" evidences from the avatar menu.")
|
|
||||||
@HideGetPremiumCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class HideGetPremiumPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
HideGetPremiumParentFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
val parentResult = HideGetPremiumParentFingerprint.result!!
|
|
||||||
HideGetPremiumFingerprint.resolve(data, parentResult.classDef)
|
|
||||||
|
|
||||||
val parentMethod = parentResult.mutableMethod
|
|
||||||
parentMethod.replaceInstruction(
|
|
||||||
parentResult.patternScanResult!!.startIndex, """
|
|
||||||
const/4 v1, 0x0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
val result = HideGetPremiumFingerprint.result!!
|
|
||||||
val method = result.mutableMethod
|
|
||||||
method.addInstructions(
|
|
||||||
result.patternScanResult!!.startIndex, """
|
|
||||||
const/16 v0, 0x8
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,16 +3,12 @@ package app.revanced.patches.music.layout.tastebuilder.annotations
|
|||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
/**
|
|
||||||
* -- Note 2022-08-05 --
|
|
||||||
* Since 5.17.xx the tastebuilder component is dismissible, so this patch is less useful
|
|
||||||
* also it is partly litho now
|
|
||||||
*/
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.21.52", "5.22.54")
|
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
internal annotation class RemoveTasteBuilderCompatibility
|
internal annotation class RemoveTasteBuilderCompatibility
|
||||||
|
|
||||||
|
|||||||
@@ -3,37 +3,42 @@ package app.revanced.patches.music.layout.tastebuilder.patch
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
|
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
|
||||||
import app.revanced.patches.music.layout.tastebuilder.fingerprints.TasteBuilderConstructorFingerprint
|
import app.revanced.patches.music.layout.tastebuilder.signatures.TasteBuilderConstructorSignature
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("tasteBuilder-remover")
|
@Name("tasteBuilder-remover")
|
||||||
@Description("Removes the \"Tell us which artists you like\" card from the home screen.")
|
@Description("Removes the \"Tell us which artists you like\" card from the Home screen. The same functionality can be triggered from the settings anyway.")
|
||||||
@RemoveTasteBuilderCompatibility
|
@RemoveTasteBuilderCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RemoveTasteBuilderPatch : BytecodePatch(
|
class RemoveTasteBuilderPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
TasteBuilderConstructorFingerprint
|
TasteBuilderConstructorSignature
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
val result = TasteBuilderConstructorFingerprint.result!!
|
val result = signatures.first().result!!
|
||||||
val method = result.mutableMethod
|
val implementation = result.method.implementation!!
|
||||||
|
|
||||||
val insertIndex = result.patternScanResult!!.endIndex - 8
|
val insertIndex = result.scanResult.endIndex - 8
|
||||||
val register = (method.implementation!!.instructions[insertIndex] as Instruction22c).registerA
|
|
||||||
method.addInstructions(
|
val register = (implementation.instructions[insertIndex] as Instruction22c).registerA
|
||||||
insertIndex, """
|
|
||||||
|
val instructionList = """
|
||||||
const/16 v1, 0x8
|
const/16 v1, 0x8
|
||||||
invoke-virtual {v${register}, v1}, Landroid/view/View;->setVisibility(I)V
|
invoke-virtual {v${register}, v1}, Landroid/view/View;->setVisibility(I)V
|
||||||
"""
|
""".trimIndent().toInstructions().toMutableList()
|
||||||
|
|
||||||
|
implementation.addInstructions(
|
||||||
|
insertIndex, instructionList
|
||||||
)
|
)
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
package app.revanced.patches.music.layout.tastebuilder.fingerprints
|
package app.revanced.patches.music.layout.tastebuilder.signatures
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
|
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("taste-builder-constructor-fingerprint")
|
@Name("taste-builder-constructor")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Lkyu;", "<init>"
|
"Lkyu;", "<init>"
|
||||||
)
|
)
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
@RemoveTasteBuilderCompatibility
|
@RemoveTasteBuilderCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object TasteBuilderConstructorFingerprint : MethodFingerprint(
|
object TasteBuilderConstructorSignature : MethodSignature(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
|
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L"), listOf(
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.NEW_INSTANCE,
|
Opcode.NEW_INSTANCE,
|
||||||
@@ -35,9 +35,9 @@ object TasteBuilderConstructorFingerprint : MethodFingerprint(
|
|||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
|
Opcode.IPUT_OBJECT,
|
||||||
Opcode.NEW_INSTANCE,
|
Opcode.NEW_INSTANCE,
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.IPUT_OBJECT
|
||||||
Opcode.CONST
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -5,9 +5,10 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
internal annotation class RemoveUpgradeButtonCompatibility
|
internal annotation class RemoveUpgradeButtonCompatibility
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package app.revanced.patches.music.layout.upgradebutton.patch
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
|
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
|
||||||
import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint
|
import app.revanced.patches.music.layout.upgradebutton.signatures.PivotBarConstructorSignature
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction22t
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction22t
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
|
||||||
@@ -20,20 +20,20 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
|||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("upgrade-button-remover")
|
@Name("upgrade-button-remover")
|
||||||
@Description("Removes the upgrade tab from the pivot bar.")
|
@Description("Remove the upgrade tab from the pivot bar in YouTube music.")
|
||||||
@RemoveUpgradeButtonCompatibility
|
@RemoveUpgradeButtonCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RemoveUpgradeButtonPatch : BytecodePatch(
|
class RemoveUpgradeButtonPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
PivotBarConstructorFingerprint
|
PivotBarConstructorSignature
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
val result = PivotBarConstructorFingerprint.result!!
|
val result = signatures.first().result!!
|
||||||
val implementation = result.mutableMethod.implementation!!
|
val implementation = result.method.implementation!!
|
||||||
|
|
||||||
val pivotBarElementFieldRef =
|
val pivotBarElementFieldRef =
|
||||||
(implementation.instructions[result.patternScanResult!!.endIndex - 1] as Instruction22c).reference
|
(implementation.instructions[result.scanResult.endIndex - 1] as Instruction22c).reference
|
||||||
|
|
||||||
val register = (implementation.instructions.first() as Instruction35c).registerC
|
val register = (implementation.instructions.first() as Instruction35c).registerC
|
||||||
// first compile all the needed instructions
|
// first compile all the needed instructions
|
||||||
@@ -43,19 +43,19 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
|
|||||||
const/4 v2, 0x3
|
const/4 v2, 0x3
|
||||||
invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
|
invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object;
|
||||||
iput-object v0, v$register, $pivotBarElementFieldRef
|
iput-object v0, v$register, $pivotBarElementFieldRef
|
||||||
""".toInstructions().toMutableList()
|
""".trimIndent().toInstructions().toMutableList()
|
||||||
|
|
||||||
|
|
||||||
// replace the instruction to retain the label at given index
|
// replace the instruction to retain the label at given index
|
||||||
implementation.replaceInstruction(
|
implementation.replaceInstruction(
|
||||||
result.patternScanResult!!.endIndex - 1, instructionList[0] // invoke-interface
|
result.scanResult.endIndex - 1, instructionList[0] // invoke-interface
|
||||||
)
|
)
|
||||||
// do not forget to remove this instruction since we added it already
|
// do not forget to remove this instruction since we added it already
|
||||||
instructionList.removeFirst()
|
instructionList.removeFirst()
|
||||||
|
|
||||||
val exitInstruction = instructionList.last() // iput-object
|
val exitInstruction = instructionList.last() // iput-object
|
||||||
implementation.addInstruction(
|
implementation.addInstruction(
|
||||||
result.patternScanResult!!.endIndex, exitInstruction
|
result.scanResult.endIndex, exitInstruction
|
||||||
)
|
)
|
||||||
// do not forget to remove this instruction since we added it already
|
// do not forget to remove this instruction since we added it already
|
||||||
instructionList.removeLast()
|
instructionList.removeLast()
|
||||||
@@ -64,12 +64,12 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
|
|||||||
instructionList.add(
|
instructionList.add(
|
||||||
2, // if-le
|
2, // if-le
|
||||||
BuilderInstruction22t(
|
BuilderInstruction22t(
|
||||||
Opcode.IF_LE, 1, 2, implementation.newLabelForIndex(result.patternScanResult!!.endIndex)
|
Opcode.IF_LE, 1, 2, implementation.newLabelForIndex(result.scanResult.endIndex)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
implementation.addInstructions(
|
implementation.addInstructions(
|
||||||
result.patternScanResult!!.endIndex, instructionList
|
result.scanResult.endIndex, instructionList
|
||||||
)
|
)
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
package app.revanced.patches.music.layout.upgradebutton.fingerprints
|
package app.revanced.patches.music.layout.upgradebutton.signatures
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
|
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("pivot-bar-constructor-fingerprint")
|
@Name("pivot-bar-constructor")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Lhfu;", "<init2>"
|
"Lhfu;", "<init2>"
|
||||||
)
|
)
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
@RemoveUpgradeButtonCompatibility
|
@RemoveUpgradeButtonCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object PivotBarConstructorFingerprint : MethodFingerprint(
|
object PivotBarConstructorSignature : MethodSignature(
|
||||||
"V",
|
"V",
|
||||||
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
listOf("L", "Z"),
|
listOf("L", "Z"),
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[Package(
|
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class MusicMicroGPatchCompatibility
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
|
||||||
|
|
||||||
@Name("cast-context-fetch-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lvvz;", "a"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@MicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object CastContextFetchFingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("Error fetching CastContext.")
|
|
||||||
)
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
|
||||||
|
|
||||||
@Name("cast-module-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Llqh;", "c"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@MicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object CastDynamiteModuleFingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl")
|
|
||||||
)
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
|
|
||||||
|
|
||||||
@Name("cast-context-fetch-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lmcf;", "c"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@MicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object CastDynamiteModuleV2Fingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("Failed to load module via V2: ")
|
|
||||||
)
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("google-play-utility-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lnuv;", "b"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@MusicMicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object GooglePlayUtilityFingerprint : MethodFingerprint(
|
|
||||||
"I",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
|
||||||
listOf("L", "I"),
|
|
||||||
strings = listOf(
|
|
||||||
"This should never happen.",
|
|
||||||
"MetadataValueReader",
|
|
||||||
"GooglePlayServicesUtil",
|
|
||||||
"com.android.vending",
|
|
||||||
"android.hardware.type.embedded"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
|
||||||
|
|
||||||
@Name("google-play-prime-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lrwi;", "a"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@MusicMicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object PrimeFingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("com.google.android.GoogleCamera", "com.android.vending")
|
|
||||||
)
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("google-play-service-checker-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lnuv;", "d"
|
|
||||||
)
|
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
|
||||||
@MusicMicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ServiceCheckFingerprint : MethodFingerprint(
|
|
||||||
"V",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
|
||||||
listOf("L", "I"),
|
|
||||||
strings = listOf("Google Play Services not available")
|
|
||||||
)
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.patch.bytecode
|
|
||||||
|
|
||||||
import app.revanced.extensions.equalsAny
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
|
||||||
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
|
||||||
import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch
|
|
||||||
import app.revanced.patches.youtube.misc.microg.patch.resource.enum.StringReplaceMode
|
|
||||||
import app.revanced.patches.music.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.music.misc.microg.fingerprints.*
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
|
||||||
import org.jf.dexlib2.iface.reference.StringReference
|
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@DependsOn([MusicMicroGResourcePatch::class])
|
|
||||||
@Name("music-microg-support")
|
|
||||||
@Description("Allows YouTube Music ReVanced to run without root and under a different package name.")
|
|
||||||
@MusicMicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class MusicMicroGBytecodePatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
ServiceCheckFingerprint,
|
|
||||||
GooglePlayUtilityFingerprint,
|
|
||||||
CastDynamiteModuleFingerprint,
|
|
||||||
CastDynamiteModuleV2Fingerprint,
|
|
||||||
CastContextFetchFingerprint,
|
|
||||||
PrimeFingerprint,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
disablePlayServiceChecks()
|
|
||||||
data.classes.forEach { classDef ->
|
|
||||||
var proxiedClass: MutableClass? = null
|
|
||||||
|
|
||||||
classDef.methods.forEach methodLoop@{ method ->
|
|
||||||
val implementation = method.implementation ?: return@methodLoop
|
|
||||||
|
|
||||||
var proxiedImplementation: MutableMethodImplementation? = null
|
|
||||||
|
|
||||||
implementation.instructions.forEachIndexed { i, instruction ->
|
|
||||||
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
|
||||||
|
|
||||||
val stringValue = ((instruction as Instruction21c).reference as StringReference).string
|
|
||||||
|
|
||||||
val replaceMode = if (stringValue.equalsAny(
|
|
||||||
"com.google.android.gms",
|
|
||||||
"com.google.android.gms.chimera",
|
|
||||||
"com.google.android.c2dm.intent.REGISTER",
|
|
||||||
"com.google.android.c2dm.permission.SEND",
|
|
||||||
"com.google.iid.TOKEN_REQUEST",
|
|
||||||
"com.google",
|
|
||||||
"com.google.android.gms.chimera.GmsIntentOperationService",
|
|
||||||
"com.google.android.gms.phenotype.internal.IPhenotypeCallbacks",
|
|
||||||
"com.google.android.gms.phenotype.internal.IPhenotypeService",
|
|
||||||
"com.google.android.gms.phenotype.service.START",
|
|
||||||
"com.google.android.gms.phenotype.PACKAGE_NAME",
|
|
||||||
"com.google.android.gms.phenotype.UPDATE",
|
|
||||||
"com.google.android.gms.phenotype",
|
|
||||||
"com.google.android.gms.auth.accounts",
|
|
||||||
"com.google.android.c2dm.intent.REGISTRATION",
|
|
||||||
"com.google.android.gsf.action.GET_GLS",
|
|
||||||
"com.google.android.gsf.login",
|
|
||||||
"content://com.google.settings/partner",
|
|
||||||
"content://com.google.android.gms.phenotype/",
|
|
||||||
"content://com.google.android.gsf.gservices",
|
|
||||||
"content://com.google.android.gsf.gservices/prefix",
|
|
||||||
"com.google.android.c2dm.intent.RECEIVE"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
StringReplaceMode.REPLACE_WITH_MICROG
|
|
||||||
} else if (stringValue.equalsAny(
|
|
||||||
"com.google.android.apps.youtube.music.SuggestionsProvider", "com.google.android.apps.youtube.music.fileprovider"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
StringReplaceMode.REPLACE_WITH_REVANCED
|
|
||||||
} else {
|
|
||||||
StringReplaceMode.DO_NOT_REPLACE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (replaceMode != StringReplaceMode.DO_NOT_REPLACE) {
|
|
||||||
if (proxiedClass == null) {
|
|
||||||
proxiedClass = data.proxy(classDef).resolve()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxiedImplementation == null) {
|
|
||||||
proxiedImplementation = proxiedClass!!.methods.first {
|
|
||||||
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
|
||||||
}.implementation!!
|
|
||||||
}
|
|
||||||
|
|
||||||
val newString = if (replaceMode == StringReplaceMode.REPLACE_WITH_REVANCED) stringValue.replace(
|
|
||||||
"com.google.android.apps.youtube.music", REVANCED_MUSIC_PACKAGE_NAME
|
|
||||||
)
|
|
||||||
else stringValue.replace("com.google", BASE_MICROG_PACKAGE_NAME)
|
|
||||||
|
|
||||||
proxiedImplementation!!.replaceInstruction(
|
|
||||||
i, BuilderInstruction21c(
|
|
||||||
Opcode.CONST_STRING, instruction.registerA, ImmutableStringReference(newString)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun disablePlayServiceChecks() {
|
|
||||||
listOf(
|
|
||||||
ServiceCheckFingerprint,
|
|
||||||
GooglePlayUtilityFingerprint,
|
|
||||||
CastDynamiteModuleFingerprint,
|
|
||||||
CastDynamiteModuleV2Fingerprint,
|
|
||||||
CastContextFetchFingerprint,
|
|
||||||
).forEach { fingerprint ->
|
|
||||||
val result = fingerprint.result!!
|
|
||||||
val stringInstructions = when (result.method.returnType.first()) {
|
|
||||||
'L' -> """
|
|
||||||
const/4 v0, 0x0
|
|
||||||
return-object v0
|
|
||||||
"""
|
|
||||||
|
|
||||||
'V' -> "return-void"
|
|
||||||
'I' -> """
|
|
||||||
const/4 v0, 0x0
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
|
|
||||||
else -> throw Exception("This case should never happen.")
|
|
||||||
}
|
|
||||||
result.mutableMethod.addInstructions(
|
|
||||||
0, stringInstructions
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val primeMethod = PrimeFingerprint.result!!.mutableMethod
|
|
||||||
val implementation = primeMethod.implementation!!
|
|
||||||
|
|
||||||
var register = 2
|
|
||||||
val index = implementation.instructions.indexOfFirst {
|
|
||||||
if (it.opcode != Opcode.CONST_STRING) return@indexOfFirst false
|
|
||||||
|
|
||||||
val instructionString = ((it as Instruction21c).reference as StringReference).string
|
|
||||||
if (instructionString != "com.google.android.apps.youtube.music") return@indexOfFirst false
|
|
||||||
|
|
||||||
register = it.registerA
|
|
||||||
return@indexOfFirst true
|
|
||||||
}
|
|
||||||
|
|
||||||
primeMethod.replaceInstruction(
|
|
||||||
index, "const-string v$register, \"$REVANCED_MUSIC_PACKAGE_NAME\""
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.patch.resource
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.ResourceData
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.impl.ResourcePatch
|
|
||||||
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
|
||||||
import app.revanced.patches.music.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
|
||||||
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME
|
|
||||||
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
|
||||||
|
|
||||||
@Name("music-microg-resource-patch")
|
|
||||||
@Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.")
|
|
||||||
@MusicMicroGPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class MusicMicroGResourcePatch : ResourcePatch() {
|
|
||||||
override fun execute(data: ResourceData): PatchResult {
|
|
||||||
|
|
||||||
val manifest = data["AndroidManifest.xml"].readText()
|
|
||||||
|
|
||||||
data["AndroidManifest.xml"].writeText(
|
|
||||||
manifest.replace(
|
|
||||||
"package=\"com.google.android.apps.youtube.music", "package=\"$REVANCED_MUSIC_PACKAGE_NAME"
|
|
||||||
).replace(
|
|
||||||
"android:label=\"@string/app_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
|
|
||||||
).replace(
|
|
||||||
"android:label=\"@string/app_launcher_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
|
|
||||||
).replace(
|
|
||||||
"android:authorities=\"com.google.android.apps.youtube.music", "android:authorities=\"$REVANCED_MUSIC_PACKAGE_NAME"
|
|
||||||
).replace(
|
|
||||||
"com.google.android.apps.youtube.music.permission.C2D_MESSAGE", "$REVANCED_MUSIC_PACKAGE_NAME.permission.C2D_MESSAGE"
|
|
||||||
).replace(
|
|
||||||
"com.google.android.c2dm", "$BASE_MICROG_PACKAGE_NAME.android.c2dm"
|
|
||||||
).replace(
|
|
||||||
"</queries>", "<package android:name=\"$BASE_MICROG_PACKAGE_NAME.android.gms\"/></queries>"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package app.revanced.patches.music.misc.microg.shared
|
|
||||||
|
|
||||||
object Constants {
|
|
||||||
internal const val BASE_MICROG_PACKAGE_NAME = "com.mgoogle"
|
|
||||||
internal const val REVANCED_MUSIC_APP_NAME = "YouTube Music ReVanced"
|
|
||||||
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,10 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54")
|
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
internal annotation class BackgroundPlayCompatibility
|
internal annotation class BackgroundPlayCompatibility
|
||||||
|
|
||||||
|
|||||||
@@ -3,32 +3,33 @@ package app.revanced.patches.music.premium.backgroundplay.patch
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
|
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
|
||||||
import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint
|
import app.revanced.patches.music.premium.backgroundplay.signatures.BackgroundPlaybackDisableSignature
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("background-play")
|
@Name("background-play")
|
||||||
@Description("Enables playing music in the background.")
|
@Description("Enable playing music in the background.")
|
||||||
@BackgroundPlayCompatibility
|
@BackgroundPlayCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class BackgroundPlayPatch : BytecodePatch(
|
class BackgroundPlayPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
BackgroundPlaybackDisableFingerprint
|
BackgroundPlaybackDisableSignature
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
BackgroundPlaybackDisableFingerprint.result!!.mutableMethod.addInstructions(
|
signatures.first().result!!.method.implementation!!.addInstructions(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
const/4 v0, 0x1
|
const/4 v0, 0x1
|
||||||
return v0
|
return v0
|
||||||
"""
|
""".trimIndent().toInstructions()
|
||||||
)
|
)
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
package app.revanced.patches.music.premium.backgroundplay.fingerprints
|
package app.revanced.patches.music.premium.backgroundplay.signatures
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.signature.implementation.method.MethodSignature
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
|
||||||
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
|
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("background-playback-disabler-fingerprint")
|
@Name("background-playback-disabler-signature")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Lafgf;", "e"
|
"Lafgf;", "e"
|
||||||
)
|
)
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
@BackgroundPlayCompatibility
|
@BackgroundPlayCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
|
object BackgroundPlaybackDisableSignature : MethodSignature(
|
||||||
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.IF_EQZ,
|
Opcode.IF_EQZ,
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.reddit.ad.general.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility([Package("com.reddit.frontpage")])
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class GeneralAdsCompatibility
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package app.revanced.patches.reddit.ad.general.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patches.reddit.ad.general.annotations.GeneralAdsCompatibility
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.reference.StringReference
|
|
||||||
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("general-reddit-ads")
|
|
||||||
@Description("Removes general ads from the Reddit frontpage and subreddits.")
|
|
||||||
@GeneralAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class GeneralAdsPatch : BytecodePatch() {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
data.classes.forEach { classDef ->
|
|
||||||
classDef.methods.forEach methodLoop@{ method ->
|
|
||||||
val implementation = method.implementation ?: return@methodLoop
|
|
||||||
|
|
||||||
implementation.instructions.forEachIndexed { i, instruction ->
|
|
||||||
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
|
||||||
if (((instruction as ReferenceInstruction).reference as StringReference).string != "AdPost") return@forEachIndexed
|
|
||||||
|
|
||||||
val proxiedClass = data.proxy(classDef).resolve()
|
|
||||||
|
|
||||||
val proxiedImplementation = proxiedClass.methods.first {
|
|
||||||
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
|
||||||
}.implementation!!
|
|
||||||
|
|
||||||
var newString = "AdPost1"
|
|
||||||
if (proxiedImplementation.instructions[i - 1].opcode == Opcode.CONST_STRING) {
|
|
||||||
newString = "SubredditPost"
|
|
||||||
}
|
|
||||||
proxiedImplementation.replaceInstruction(
|
|
||||||
i, BuilderInstruction21c(
|
|
||||||
Opcode.CONST_STRING, (proxiedImplementation.instructions[i] as BuilderInstruction21c).registerA, ImmutableStringReference(newString)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.reddit.layout.premiumicon.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility([Package("com.reddit.frontpage")])
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class PremiumIconCompatibility
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package app.revanced.patches.reddit.layout.premiumicon.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.reddit.layout.premiumicon.annotations.PremiumIconCompatibility
|
|
||||||
|
|
||||||
@Name("premium-icon-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lcom/reddit/domain/model/MyAccount;", "isPremiumSubscriber"
|
|
||||||
)
|
|
||||||
@PremiumIconCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object PremiumIconFingerprint : MethodFingerprint(
|
|
||||||
"Z",
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("MyAccount;") && methodDef.name == "isPremiumSubscriber"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package app.revanced.patches.reddit.layout.premiumicon.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patches.reddit.layout.premiumicon.annotations.PremiumIconCompatibility
|
|
||||||
import app.revanced.patches.reddit.layout.premiumicon.fingerprints.PremiumIconFingerprint
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("premium-icon-reddit")
|
|
||||||
@Description("Unlocking Premium Icons in reddit app.")
|
|
||||||
@PremiumIconCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class PremiumIconPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
PremiumIconFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
val method = PremiumIconFingerprint.result!!.mutableMethod
|
|
||||||
method.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x1
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.ad.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[
|
|
||||||
Package("com.ss.android.ugc.trill"),
|
|
||||||
Package("com.zhiliaoapp.musically")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class TiktokAdsCompatibility
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.ad.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.tiktok.ad.annotations.TiktokAdsCompatibility
|
|
||||||
|
|
||||||
@Name("convert-help-v2-feeditemlist-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lbeancopy/ConvertHelp;",
|
|
||||||
"com${'$'}ss${'$'}ugc${'$'}aweme${'$'}proto${'$'}aweme_v2_feed_response${'$'}${'$'}com${'$'}ss${'$'}android${'$'}ugc${'$'}aweme${'$'}feed${'$'}model${'$'}FeedItemList",
|
|
||||||
)
|
|
||||||
@TiktokAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ConvertHelpFeedItemListFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("/ConvertHelp;") &&
|
|
||||||
methodDef.name.endsWith("${'$'}FeedItemList")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.ad.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.tiktok.ad.annotations.TiktokAdsCompatibility
|
|
||||||
|
|
||||||
@Name("feed-item-clone-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;",
|
|
||||||
"clone",
|
|
||||||
)
|
|
||||||
@TiktokAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object FeedItemListCloneFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("/FeedItemList;") && methodDef.name == "clone"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.ad.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patches.tiktok.ad.annotations.TiktokAdsCompatibility
|
|
||||||
import app.revanced.patches.tiktok.ad.fingerprints.ConvertHelpFeedItemListFingerprint
|
|
||||||
import app.revanced.patches.tiktok.ad.fingerprints.FeedItemListCloneFingerprint
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("tiktok-ads")
|
|
||||||
@Description("Removes ads from TikTok.")
|
|
||||||
@TiktokAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class TiktokAdsPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
FeedItemListCloneFingerprint,
|
|
||||||
ConvertHelpFeedItemListFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
listOf(
|
|
||||||
FeedItemListCloneFingerprint,
|
|
||||||
ConvertHelpFeedItemListFingerprint
|
|
||||||
).forEach { fingerprint ->
|
|
||||||
val method = fingerprint.result!!.mutableMethod
|
|
||||||
// iterate all instructions in the clone method
|
|
||||||
for ((index, instruction) in method.implementation!!.instructions.withIndex()) {
|
|
||||||
// conditions for the instruction we need
|
|
||||||
if (instruction.opcode.ordinal != Opcode.IPUT_OBJECT.ordinal) continue
|
|
||||||
val preloadAdsFieldInstruction = (instruction as? ReferenceInstruction)
|
|
||||||
if ((preloadAdsFieldInstruction?.reference as? FieldReference)?.name != "preloadAds") continue
|
|
||||||
|
|
||||||
// set null instead of the field "preloadAds"
|
|
||||||
val overrideRegister = (preloadAdsFieldInstruction as TwoRegisterInstruction).registerA
|
|
||||||
method.addInstruction(
|
|
||||||
index,
|
|
||||||
"const/4 v$overrideRegister, 0x0"
|
|
||||||
)
|
|
||||||
return@forEach
|
|
||||||
}
|
|
||||||
return PatchResultError("Can not find required instruction.")
|
|
||||||
}
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.downloads.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[
|
|
||||||
Package("com.ss.android.ugc.trill"),
|
|
||||||
Package("com.zhiliaoapp.musically")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class DownloadsCompatibility
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.downloads.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("acl-common-share-get-code")
|
|
||||||
@MatchingMethod("ACLCommonShare", "getCode")
|
|
||||||
@DownloadsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ACLCommonShareFingerprint : MethodFingerprint(
|
|
||||||
"I",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("/ACLCommonShare;") &&
|
|
||||||
methodDef.name == "getCode"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.downloads.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("acl-common-share-get-show-type")
|
|
||||||
@MatchingMethod("ACLCommonShare", "getShowType")
|
|
||||||
@DownloadsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ACLCommonShareFingerprint2 : MethodFingerprint(
|
|
||||||
"I",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("/ACLCommonShare;") &&
|
|
||||||
methodDef.name == "getShowType"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.downloads.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("acl-common-share-get-transcode")
|
|
||||||
@MatchingMethod("ACLCommonShare", "getTranscode")
|
|
||||||
@DownloadsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ACLCommonShareFingerprint3 : MethodFingerprint(
|
|
||||||
"I",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("/ACLCommonShare;") &&
|
|
||||||
methodDef.name == "getTranscode"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.downloads.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.replaceInstructions
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility
|
|
||||||
import app.revanced.patches.tiktok.interaction.downloads.fingerprints.*
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("tiktok-download")
|
|
||||||
@Description("Remove restrictions on downloads video.")
|
|
||||||
@DownloadsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class DownloadsPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
ACLCommonShareFingerprint,
|
|
||||||
ACLCommonShareFingerprint2,
|
|
||||||
ACLCommonShareFingerprint3
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
val method1 = ACLCommonShareFingerprint.result!!.mutableMethod
|
|
||||||
method1.replaceInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x0
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
val method2 = ACLCommonShareFingerprint2.result!!.mutableMethod
|
|
||||||
method2.replaceInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x2
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
//Download videos without watermark.
|
|
||||||
val method3 = ACLCommonShareFingerprint3.result!!.mutableMethod
|
|
||||||
method3.replaceInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x1
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.seekbar.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[
|
|
||||||
Package("com.ss.android.ugc.trill"),
|
|
||||||
Package("com.zhiliaoapp.musically")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class SeekbarCompatibility
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.seekbar.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.tiktok.interaction.seekbar.annotations.SeekbarCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("aweme-get-video-control")
|
|
||||||
@MatchingMethod("Aweme", "getVideoControl")
|
|
||||||
@SeekbarCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object AwemeGetVideoControlFingerprint : MethodFingerprint(
|
|
||||||
"L",
|
|
||||||
AccessFlags.PUBLIC.value,
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("/Aweme;") && methodDef.name == "getVideoControl"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package app.revanced.patches.tiktok.interaction.seekbar.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patches.tiktok.interaction.seekbar.annotations.SeekbarCompatibility
|
|
||||||
import app.revanced.patches.tiktok.interaction.seekbar.fingerprints.*
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction11n
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction22c
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("tiktok-seekbar")
|
|
||||||
@Description("Show progress bar for all video.")
|
|
||||||
@SeekbarCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class TiktokSeekbarPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
AwemeGetVideoControlFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
//Get VideoControl FieldReference
|
|
||||||
val videoControl = data.findClass { it.type.endsWith("/VideoControl;") }
|
|
||||||
?: return PatchResultError("Can not find target class")
|
|
||||||
val fieldList = videoControl.immutableClass.fields.associateBy { field -> field.name }
|
|
||||||
|
|
||||||
val method = AwemeGetVideoControlFingerprint.result!!.mutableMethod
|
|
||||||
val implementation = method.implementation!!
|
|
||||||
implementation.addInstructions(
|
|
||||||
1, listOf(
|
|
||||||
BuilderInstruction11n(Opcode.CONST_4, 1, 1),
|
|
||||||
BuilderInstruction22c(Opcode.IPUT, 1, 0, fieldList["showProgressBar"]!!),
|
|
||||||
BuilderInstruction22c(Opcode.IPUT, 1, 0, fieldList["draftProgressBar"]!!)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.twitter.ad.timeline.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility([Package("com.twitter.android")])
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class TimelineAdsCompatibility
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package app.revanced.patches.twitter.ad.timeline.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.twitter.ad.timeline.annotations.TimelineAdsCompatibility
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("timeline-tweet-json-parser-fingerprint")
|
|
||||||
@MatchingMethod("LJsonTimelineTweet\$\$JsonObjectMapper;", "parseField")
|
|
||||||
@TimelineAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object TimelineTweetJsonParserFingerprint : MethodFingerprint(
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.GOTO,
|
|
||||||
Opcode.SGET_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.CHECK_CAST,
|
|
||||||
Opcode.IPUT_OBJECT,
|
|
||||||
Opcode.RETURN_VOID,
|
|
||||||
), strings = listOf("tweetPromotedMetadata", "promotedMetadata", "hasModeratedReplies", "conversationAnnotation"),
|
|
||||||
customFingerprint = { methodDef -> methodDef.name == "parseField" }
|
|
||||||
)
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package app.revanced.patches.twitter.ad.timeline.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.instruction
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
|
||||||
import app.revanced.patches.twitter.ad.timeline.annotations.TimelineAdsCompatibility
|
|
||||||
import app.revanced.patches.twitter.ad.timeline.fingerprints.TimelineTweetJsonParserFingerprint
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction22c
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
|
||||||
import org.jf.dexlib2.iface.reference.StringReference
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("timeline-ads")
|
|
||||||
@Description("Removes ads from the Twitter timeline.")
|
|
||||||
@TimelineAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class TimelineAdsPatch : BytecodePatch(
|
|
||||||
listOf(TimelineTweetJsonParserFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
if (removePromotedAds())
|
|
||||||
return PatchResultError("The instruction for the tweet id field could not be found")
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removePromotedAds(): Boolean {
|
|
||||||
val (parserFingerprintResult, parserMethod, instructions) = TimelineTweetJsonParserFingerprint.unwrap()
|
|
||||||
|
|
||||||
// Anchor index
|
|
||||||
val tweetIdFieldInstructionIndex = instructions.indexOfFirst { instruction ->
|
|
||||||
if (instruction.opcode.ordinal != Opcode.CONST_STRING.ordinal) return@indexOfFirst false
|
|
||||||
if (((instruction as? ReferenceInstruction)?.reference as StringReference).string != "tweetSocialProof") return@indexOfFirst false
|
|
||||||
|
|
||||||
// Use the above conditions as an anchor to find the index for the instruction with the field we need
|
|
||||||
return@indexOfFirst true
|
|
||||||
} - 2 // This is where the instruction with the field is located
|
|
||||||
|
|
||||||
// Reference to the tweetId field for of the timeline tweet
|
|
||||||
val tweetIdFieldReference =
|
|
||||||
(parserMethod.instruction(tweetIdFieldInstructionIndex) as? BuilderInstruction22c)?.reference as? FieldReference
|
|
||||||
?: return true
|
|
||||||
|
|
||||||
// Set the tweetId field to null
|
|
||||||
// This will cause twitter to not show the promoted ads, because we set it to null, when the tweet is promoted
|
|
||||||
parserFingerprintResult.mutableMethod.addInstructions(
|
|
||||||
parserFingerprintResult.patternScanResult!!.startIndex + 1,
|
|
||||||
"""
|
|
||||||
const/4 v2, 0x0
|
|
||||||
iput-object v2, p0, Lcom/twitter/model/json/timeline/urt/JsonTimelineTweet;->${tweetIdFieldReference.name}:Ljava/lang/String;
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MethodFingerprint.unwrap(): Triple<MethodFingerprintResult, MutableMethod, MutableList<BuilderInstruction>> {
|
|
||||||
val parserFingerprintResult = this.result!!
|
|
||||||
val parserMethod = parserFingerprintResult.mutableMethod
|
|
||||||
val instructions = parserMethod.implementation!!.instructions
|
|
||||||
|
|
||||||
return Triple(parserFingerprintResult, parserMethod, instructions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.firebasegetcert.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility([Package("de.dwd.warnapp")])
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class FirebaseGetCertPatchCompatibility
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.warnwetter.misc.firebasegetcert.annotations.FirebaseGetCertPatchCompatibility
|
|
||||||
|
|
||||||
@Name("messaging-app-certificate-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lcom/google/firebase/installations/remote/c;", "f"
|
|
||||||
)
|
|
||||||
@FirebaseGetCertPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object GetMessagingCertFingerprint : MethodFingerprint(
|
|
||||||
"Ljava/lang/String;",
|
|
||||||
strings = listOf(
|
|
||||||
"ContentValues",
|
|
||||||
"Could not get fingerprint hash for package: ",
|
|
||||||
"No such package: "
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.warnwetter.misc.firebasegetcert.annotations.FirebaseGetCertPatchCompatibility
|
|
||||||
|
|
||||||
@Name("registration-app-certificate-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lcom/google/firebase/remoteconfig/internal/ConfigFetchHttpClient;", "f"
|
|
||||||
)
|
|
||||||
@FirebaseGetCertPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object GetReqistrationCertFingerprint : MethodFingerprint(
|
|
||||||
"Ljava/lang/String;",
|
|
||||||
strings = listOf(
|
|
||||||
"FirebaseRemoteConfig",
|
|
||||||
"Could not get fingerprint hash for package: ",
|
|
||||||
"No such package: "
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.firebasegetcert.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints.*
|
|
||||||
import app.revanced.patches.warnwetter.misc.firebasegetcert.annotations.FirebaseGetCertPatchCompatibility
|
|
||||||
|
|
||||||
@Name("spoof-cert-patch")
|
|
||||||
@Description("Spoofs the X-Android-Cert header.")
|
|
||||||
@FirebaseGetCertPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class FirebaseGetCertPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
GetReqistrationCertFingerprint,
|
|
||||||
GetMessagingCertFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
val spoofedInstruction =
|
|
||||||
"""
|
|
||||||
const-string v0, "0799DDF0414D3B3475E88743C91C0676793ED450"
|
|
||||||
return-object v0
|
|
||||||
"""
|
|
||||||
|
|
||||||
val registrationCertMethod = GetReqistrationCertFingerprint.result!!.mutableMethod
|
|
||||||
val messagingCertMethod = GetMessagingCertFingerprint.result!!.mutableMethod
|
|
||||||
|
|
||||||
registrationCertMethod.addInstructions(
|
|
||||||
0,
|
|
||||||
spoofedInstruction
|
|
||||||
)
|
|
||||||
messagingCertMethod.addInstructions(
|
|
||||||
0,
|
|
||||||
spoofedInstruction
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.promocode.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility([Package("de.dwd.warnapp")])
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class PromoCodeUnlockCompatibility
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.promocode.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.warnwetter.misc.promocode.annotations.PromoCodeUnlockCompatibility
|
|
||||||
|
|
||||||
@Name("promo-code-unlock-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
"Lde/dwd/warnapp/model/PromoTokenVerification;", "isValid"
|
|
||||||
)
|
|
||||||
@PromoCodeUnlockCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object PromoCodeUnlockFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("PromoTokenVerification;") && methodDef.name == "isValid"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package app.revanced.patches.warnwetter.misc.promocode.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import app.revanced.patches.warnwetter.misc.firebasegetcert.patch.FirebaseGetCertPatch
|
|
||||||
import app.revanced.patches.warnwetter.misc.promocode.annotations.PromoCodeUnlockCompatibility
|
|
||||||
import app.revanced.patches.warnwetter.misc.promocode.fingerprints.PromoCodeUnlockFingerprint
|
|
||||||
|
|
||||||
@DependsOn(
|
|
||||||
[
|
|
||||||
FirebaseGetCertPatch::class
|
|
||||||
]
|
|
||||||
)
|
|
||||||
@Patch
|
|
||||||
@Name("promo-code-unlock")
|
|
||||||
@Description("Disables the validation of promo code. Any code will work to unlock all features.")
|
|
||||||
@PromoCodeUnlockCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class PromoCodeUnlockPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
PromoCodeUnlockFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
val method = PromoCodeUnlockFingerprint.result!!.mutableMethod
|
|
||||||
method.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
const/4 v0, 0x1
|
|
||||||
return v0
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.youtube", arrayOf("17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35", "17.33.42")
|
"com.google.android.youtube", arrayOf("17.19.36", "17.20.37", "17.22.36")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package app.revanced.patches.youtube.ad.general.bytecode.extensions
|
|||||||
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.softCompareTo
|
import app.revanced.patcher.extensions.softCompareTo
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction
|
import org.jf.dexlib2.builder.BuilderInstruction
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ import app.revanced.extensions.injectHideCall
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.implementation.BytecodeData
|
||||||
|
import app.revanced.patcher.data.implementation.proxy
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.implementation.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultError
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
@@ -21,11 +22,9 @@ import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensi
|
|||||||
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.insertBlocks
|
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.insertBlocks
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.toDescriptor
|
import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensions.toDescriptor
|
||||||
import app.revanced.patches.youtube.ad.general.bytecode.utils.MethodUtils.createMutableMethod
|
import app.revanced.patches.youtube.ad.general.bytecode.utils.MethodUtils.createMutableMethod
|
||||||
|
import app.revanced.patches.youtube.ad.general.resource.patch.GeneralResourceAdsPatch
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
|
|
||||||
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
|
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
import org.jf.dexlib2.builder.instruction.*
|
import org.jf.dexlib2.builder.instruction.*
|
||||||
@@ -41,12 +40,16 @@ import org.jf.dexlib2.iface.reference.StringReference
|
|||||||
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class, SettingsPatch::class])
|
@Dependencies(
|
||||||
|
dependencies = [ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class, GeneralResourceAdsPatch::class]
|
||||||
|
)
|
||||||
@Name("general-ads")
|
@Name("general-ads")
|
||||||
@Description("Removes general ads.")
|
@Description("Patch to remove general ads in bytecode.")
|
||||||
@GeneralAdsCompatibility
|
@GeneralAdsCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class GeneralBytecodeAdsPatch : BytecodePatch() {
|
class GeneralBytecodeAdsPatch : BytecodePatch(
|
||||||
|
listOf()
|
||||||
|
) {
|
||||||
// a constant used by litho
|
// a constant used by litho
|
||||||
private val lithoConstant = 0xaed2868
|
private val lithoConstant = 0xaed2868
|
||||||
|
|
||||||
@@ -60,8 +63,8 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
"endscreen_element_layout_icon",
|
"endscreen_element_layout_icon",
|
||||||
"promoted_video_item_land",
|
"promoted_video_item_land",
|
||||||
"promoted_video_item_full_bleed",
|
"promoted_video_item_full_bleed",
|
||||||
).map { name ->
|
).map {
|
||||||
ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.name == name }.id
|
ResourceIdMappingProviderResourcePatch.resourceMappings[it]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
private val stringReferences = arrayOf(
|
private val stringReferences = arrayOf(
|
||||||
@@ -71,135 +74,6 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
SettingsPatch.PreferenceScreen.ADS.addPreferences(
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_home_ads_removal",
|
|
||||||
StringResource("revanced_home_ads_removal_title", "Remove home ads"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_home_ads_removal_summary_on", "Home ads are hidden"),
|
|
||||||
StringResource("revanced_home_ads_removal_summary_off", "Home ads are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_ad_removal",
|
|
||||||
StringResource("revanced_adremover_ad_removal_enabled_title", "Remove general ads"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_ad_removal_enabled_summary_on", "General ads are hidden"),
|
|
||||||
StringResource("revanced_adremover_ad_removal_enabled_summary_off", "General ads are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_merchandise",
|
|
||||||
StringResource("revanced_adremover_merchandise_enabled_title", "Remove merchandise banners"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_merchandise_enabled_summary_on", "Merchandise banners are hidden"),
|
|
||||||
StringResource("revanced_adremover_merchandise_enabled_summary_off", "Merchandise banners are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_community_posts_removal",
|
|
||||||
StringResource("revanced_adremover_community_posts_enabled_title", "Remove community posts"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_community_posts_enabled_summary_on", "Community posts are hidden"),
|
|
||||||
StringResource("revanced_adremover_community_posts_enabled_summary_off", "Community posts are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_compact_banner_removal",
|
|
||||||
StringResource("revanced_adremover_compact_banner_enabled_title", "Remove compact banners"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_compact_banner_enabled_summary_on", "Compact banners are hidden"),
|
|
||||||
StringResource("revanced_adremover_compact_banner_enabled_summary_off", "Compact banners are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_comments_removal",
|
|
||||||
StringResource("revanced_adremover_comments_enabled_title", "Remove comments section"),
|
|
||||||
false,
|
|
||||||
StringResource("revanced_adremover_comments_enabled_summary_on", "Comment section is hidden"),
|
|
||||||
StringResource("revanced_adremover_comments_enabled_summary_off", "Comment section is shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_movie",
|
|
||||||
StringResource("revanced_adremover_movie_enabled_title", "Remove movies section"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_movie_enabled_summary_on", "Movies section is hidden"),
|
|
||||||
StringResource("revanced_adremover_movie_enabled_summary_off", "Movies section is shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_feed_survey",
|
|
||||||
StringResource("revanced_adremover_feed_survey_enabled_title", "Remove feed surveys"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_feed_survey_enabled_summary_on", "Feed surveys are hidden"),
|
|
||||||
StringResource("revanced_adremover_feed_survey_enabled_summary_off", "Feed surveys are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_shorts_shelf",
|
|
||||||
StringResource("revanced_adremover_shorts_shelf_enabled_title", "Remove shorts shelf"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_shorts_shelf_enabled_summary_on", "Shorts shelves are hidden"),
|
|
||||||
StringResource("revanced_adremover_shorts_shelf_enabled_summary_off", "Shorts shelves are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_community_guidelines",
|
|
||||||
StringResource("revanced_adremover_community_guidelines_enabled_title", "Remove community guidelines"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_community_guidelines_enabled_summary_on", "Community guidelines are hidden"),
|
|
||||||
StringResource("revanced_adremover_community_guidelines_enabled_summary_off", "Community guidelines are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_emergency_box_removal",
|
|
||||||
StringResource("revanced_adremover_emergency_box_enabled_title", "Remove emergency boxes"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_emergency_box_enabled_summary_on", "Emergency boxes are hidden"),
|
|
||||||
StringResource("revanced_adremover_emergency_box_enabled_summary_off", "Emergency boxes are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_info_panel",
|
|
||||||
StringResource("revanced_adremover_info_panel_enabled_title", "Remove info panels"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_info_panel_enabled_summary_on", "Merchandise banners are hidden"),
|
|
||||||
StringResource("revanced_adremover_info_panel_enabled_summary_off", "Merchandise banners are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_medical_panel",
|
|
||||||
StringResource("revanced_adremover_medical_panel_enabled_title", "Remove medical panels"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_medical_panel_enabled_summary_on", "Medical panels are hidden"),
|
|
||||||
StringResource("revanced_adremover_medical_panel_enabled_summary_off", "Medical panels are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_paid_content",
|
|
||||||
StringResource("revanced_adremover_paid_content_enabled_title", "Remove paid content"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"),
|
|
||||||
StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_suggested",
|
|
||||||
StringResource("revanced_adremover_suggested_enabled_title", "Remove personal suggestions"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_suggested_enabled_summary_on", "Personal suggestions are hidden"),
|
|
||||||
StringResource("revanced_adremover_suggested_enabled_summary_off", "Personal suggestions are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_hide_suggestions",
|
|
||||||
StringResource("revanced_adremover_hide_suggestions_enabled_title", "Hide suggestions"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_hide_suggestions_enabled_summary_on", "Suggestions are hidden"),
|
|
||||||
StringResource("revanced_adremover_hide_suggestions_enabled_summary_off", "Suggestions are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_hide_latest_posts",
|
|
||||||
StringResource("revanced_adremover_hide_latest_posts_enabled_title", "Hide latest posts"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_hide_latest_posts_enabled_summary_on", "Latest posts are hidden"),
|
|
||||||
StringResource("revanced_adremover_hide_latest_posts_enabled_summary_off", "Latest posts are shown")
|
|
||||||
),
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_adremover_hide_channel_guidelines",
|
|
||||||
StringResource("revanced_adremover_hide_channel_guidelines_enabled_title", "Hide channel guidelines"),
|
|
||||||
true,
|
|
||||||
StringResource("revanced_adremover_hide_channel_guidelines_enabled_summary_on", "Channel guidelines are hidden"),
|
|
||||||
StringResource("revanced_adremover_hide_channel_guidelines_enabled_summary_off", "Channel guidelines are shown")
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
// iterating through all classes is expensive
|
// iterating through all classes is expensive
|
||||||
for (classDef in data.classes) {
|
for (classDef in data.classes) {
|
||||||
var mutableClass: MutableClass? = null
|
var mutableClass: MutableClass? = null
|
||||||
@@ -259,7 +133,6 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
if (mutableMethod == null) mutableMethod =
|
if (mutableMethod == null) mutableMethod =
|
||||||
mutableClass!!.findMutableMethodOf(method)
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
//ToDo: Add Settings toggle for whatever this is
|
|
||||||
mutableMethod!!.implementation!!.removeInstruction(removeIndex)
|
mutableMethod!!.implementation!!.removeInstruction(removeIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,11 +148,11 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
mutableClass!!.findMutableMethodOf(method)
|
mutableClass!!.findMutableMethodOf(method)
|
||||||
|
|
||||||
// TODO: dynamically get registers
|
// TODO: dynamically get registers
|
||||||
mutableMethod!!.addInstructions(
|
mutableMethod!!.implementation!!.addInstructions(
|
||||||
insertIndex, """
|
insertIndex, """
|
||||||
const/16 v1, 0x8
|
const/16 v1, 0x8
|
||||||
invoke-virtual {v0,v1}, Landroid/widget/FrameLayout;->setVisibility(I)V
|
invoke-virtual {v0,v1}, Landroid/widget/FrameLayout;->setVisibility(I)V
|
||||||
"""
|
""".trimIndent().toInstructions()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,6 +179,7 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Opcode.CONST_STRING -> {
|
Opcode.CONST_STRING -> {
|
||||||
|
|
||||||
when (((instruction as Instruction21c).reference as StringReference).string) {
|
when (((instruction as Instruction21c).reference as StringReference).string) {
|
||||||
stringReferences[0] -> {
|
stringReferences[0] -> {
|
||||||
val stringInstruction = instructions.elementAt(3)
|
val stringInstruction = instructions.elementAt(3)
|
||||||
@@ -318,7 +192,6 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
|
|
||||||
// return the method
|
// return the method
|
||||||
val insertIndex = 1 // after super constructor
|
val insertIndex = 1 // after super constructor
|
||||||
//ToDo: Add setting here
|
|
||||||
mutableMethod!!.implementation!!.addInstruction(
|
mutableMethod!!.implementation!!.addInstruction(
|
||||||
insertIndex, BuilderInstruction10x(Opcode.RETURN_VOID)
|
insertIndex, BuilderInstruction10x(Opcode.RETURN_VOID)
|
||||||
)
|
)
|
||||||
@@ -331,23 +204,23 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
stringReferences[2] -> { // Litho ads
|
stringReferences[2] -> { // Litho ads
|
||||||
// create proxied method.
|
// create proxied method.
|
||||||
val proxy = data.proxy(classDef)
|
val proxy = data.proxy(classDef)
|
||||||
val proxiedClass = proxy.resolve()
|
val mutableClass = proxy.resolve()
|
||||||
|
|
||||||
// add getIsEmpty method
|
// add getIsEmpty method
|
||||||
proxiedClass.addGetIsEmptyMethod()
|
mutableClass.addGetIsEmptyMethod()
|
||||||
|
|
||||||
// get required method to patch and get references from
|
// get required method to patch and get references from
|
||||||
val lithoMethod = getLithoMethod(proxiedClass)
|
val lithoMethod = getLithoMethod(mutableClass)
|
||||||
?: return PatchResultError("Could not find required litho method to patch.")
|
?: return PatchResultError("Could not find required litho method to patch.")
|
||||||
val lithoMethodImplementation = lithoMethod.implementation!!
|
val lithoMethodImplementation = lithoMethod.implementation!!
|
||||||
|
|
||||||
// create and add getTemplateName method
|
// create and add getTemplateName method
|
||||||
val getTemplateMethod =
|
val getTemplateMethod =
|
||||||
proxiedClass.createGetTemplateNameMethod(lithoMethodImplementation)
|
mutableClass.createGetTemplateNameMethod(lithoMethodImplementation)
|
||||||
proxiedClass.addMethod(getTemplateMethod)
|
mutableClass.addMethod(getTemplateMethod)
|
||||||
|
|
||||||
val lithoInstructions = lithoMethodImplementation.instructions
|
val lithoInstructions = lithoMethodImplementation.instructions
|
||||||
val thisType = proxiedClass.type
|
val thisType = mutableClass.type
|
||||||
val templateNameParameterType = getTemplateMethod.parameterTypes.first()
|
val templateNameParameterType = getTemplateMethod.parameterTypes.first()
|
||||||
|
|
||||||
// get reference descriptors
|
// get reference descriptors
|
||||||
@@ -369,23 +242,25 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
BuilderInstruction21t(Opcode.IF_EQZ, 1, lithoRemoveLabel)
|
BuilderInstruction21t(Opcode.IF_EQZ, 1, lithoRemoveLabel)
|
||||||
|
|
||||||
// create blocks
|
// create blocks
|
||||||
|
val parameters = lithoMethod.parameterTypes.joinToString("") { it }
|
||||||
|
val registers = lithoMethodImplementation.registerCount
|
||||||
val block1 = """
|
val block1 = """
|
||||||
invoke-static/range {p3}, $thisType->getTemplateName($templateNameParameterType)Ljava/lang/String;
|
invoke-static/range {p3}, $thisType->getTemplateName($templateNameParameterType)Ljava/lang/String;
|
||||||
move-result-object v0
|
move-result-object v0
|
||||||
""".toInstructions(lithoMethod)
|
""".trimIndent().toInstructions(parameters, registers, false)
|
||||||
val block2 = """
|
val block2 = """
|
||||||
move-object/from16 v1, p3
|
move-object/from16 v1, p3
|
||||||
iget-object v2, v1, $templateNameParameterType->b:Ljava/nio/ByteBuffer;
|
iget-object v2, v1, $templateNameParameterType->b:Ljava/nio/ByteBuffer;
|
||||||
invoke-static {v0, v2}, Lapp/revanced/integrations/patches/GeneralBytecodeAdsPatch;->containsAd(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z
|
invoke-static {v0, v2}, Lfi/razerman/youtube/litho/LithoAdRemoval;->containsAd(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z
|
||||||
move-result v1
|
move-result v1
|
||||||
""".toInstructions(lithoMethod)
|
""".trimIndent().toInstructions(parameters, registers, false)
|
||||||
val block3 = """
|
val block3 = """
|
||||||
move-object/from16 v2, p1
|
move-object/from16 v2, p1
|
||||||
invoke-static {v2}, $descriptor1
|
invoke-static {v2}, $descriptor1
|
||||||
move-result-object v0
|
move-result-object v0
|
||||||
iget-object v0, v0, $descriptor2
|
iget-object v0, v0, $descriptor2
|
||||||
return-object v0
|
return-object v0
|
||||||
""".toInstructions(lithoMethod)
|
""".trimIndent().toInstructions(parameters, registers, false)
|
||||||
|
|
||||||
// insert blocks and branch instructions
|
// insert blocks and branch instructions
|
||||||
lithoMethodImplementation.insertBlocks(
|
lithoMethodImplementation.insertBlocks(
|
||||||
@@ -496,7 +371,7 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
const v0, $lithoConstant
|
const v0, $lithoConstant
|
||||||
invoke-static {p0, v0}, ${descriptors[1]}
|
invoke-static {p0, v0}, ${descriptors[1]}
|
||||||
move-result-object p0
|
move-result-object p0
|
||||||
""".toInstructions()
|
""".trimIndent().toInstructions()
|
||||||
val block2 = """
|
val block2 = """
|
||||||
invoke-static {p0}, ${descriptors[2]}
|
invoke-static {p0}, ${descriptors[2]}
|
||||||
move-result-object p0
|
move-result-object p0
|
||||||
@@ -504,12 +379,12 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
|
|||||||
move-result-object v0
|
move-result-object v0
|
||||||
invoke-static {v0}, ${this.type}->getIsEmpty(Ljava/lang/String;)Z
|
invoke-static {v0}, ${this.type}->getIsEmpty(Ljava/lang/String;)Z
|
||||||
move-result v0
|
move-result v0
|
||||||
""".toInstructions()
|
""".trimIndent().toInstructions()
|
||||||
val block3 = """
|
val block3 = """
|
||||||
invoke-virtual {p0}, ${descriptors[3]}
|
invoke-virtual {p0}, ${descriptors[3]}
|
||||||
move-result-object p0
|
move-result-object p0
|
||||||
return-object p0
|
return-object p0
|
||||||
""".toInstructions()
|
""".trimIndent().toInstructions()
|
||||||
|
|
||||||
// create target instruction
|
// create target instruction
|
||||||
val targetInstruction = BuilderInstruction11n(Opcode.CONST_4, 1, 0)
|
val targetInstruction = BuilderInstruction11n(Opcode.CONST_4, 1, 0)
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package app.revanced.patches.youtube.ad.general.resource.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.doRecursively
|
||||||
|
import app.revanced.extensions.startsWithAny
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.implementation.ResourceData
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
|
import app.revanced.patcher.patch.implementation.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResult
|
||||||
|
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
|
||||||
|
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
@Dependencies(dependencies = [FixLocaleConfigErrorPatch::class])
|
||||||
|
@Name("general-resource-ads")
|
||||||
|
@Description("Patch to remove general ads in resources.")
|
||||||
|
@GeneralAdsCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class GeneralResourceAdsPatch : ResourcePatch() {
|
||||||
|
// list of resource file names which need to be hidden
|
||||||
|
private val resourceFileNames = arrayOf(
|
||||||
|
"compact_promoted_video_item.xml",
|
||||||
|
"inline_muted_metadata_swap.xml",
|
||||||
|
"interstitial_promo_view.xml",
|
||||||
|
"pip_ad_overlay.xml",
|
||||||
|
"promoted_",
|
||||||
|
"watch_metadata_companion_cards.xml",
|
||||||
|
//"watch_while_activity.xml" // FIXME: find out why patching this resource fails
|
||||||
|
)
|
||||||
|
|
||||||
|
// the attributes to change the value of
|
||||||
|
private val replacements = arrayOf(
|
||||||
|
"height",
|
||||||
|
"width",
|
||||||
|
"marginTop",
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
data.forEach {
|
||||||
|
if (!it.name.startsWithAny(*resourceFileNames)) return@forEach
|
||||||
|
|
||||||
|
// for each file in the "layouts" directory replace all necessary attributes content
|
||||||
|
data.getXmlEditor(it.absolutePath).use { editor ->
|
||||||
|
editor.file.doRecursively { node ->
|
||||||
|
replacements.forEach replacement@{ replacement ->
|
||||||
|
if (node !is Element) return@replacement
|
||||||
|
|
||||||
|
node.getAttributeNode("android:layout_$replacement")?.let { attribute ->
|
||||||
|
attribute.textContent = "1.0dip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.ad.infocardsuggestions.annotations
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
|
||||||
import app.revanced.patcher.annotation.Package
|
|
||||||
|
|
||||||
@Compatibility(
|
|
||||||
[Package(
|
|
||||||
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35", "17.33.42")
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
|
||||||
internal annotation class HideInfocardSuggestionsCompatibility
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.ad.infocardsuggestions.annotations.HideInfocardSuggestionsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("hide-infocard-suggestions-fingerprint")
|
|
||||||
@MatchingMethod("Liff;", "i")
|
|
||||||
@FuzzyPatternScanMethod(2)
|
|
||||||
@HideInfocardSuggestionsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object HideInfocardSuggestionsFingerprint : MethodFingerprint(
|
|
||||||
"Ljava/lang/Boolean;",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
strings = listOf("vibrator")
|
|
||||||
)
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.ad.infocardsuggestions.annotations.HideInfocardSuggestionsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("hide-infocard-suggestions-parent-fingerprint")
|
|
||||||
@MatchingMethod("Liff;", "lE")
|
|
||||||
@FuzzyPatternScanMethod(2)
|
|
||||||
@HideInfocardSuggestionsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object HideInfocardSuggestionsParentFingerprint : MethodFingerprint(
|
|
||||||
"Ljava/lang/String;",
|
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
strings = listOf("player_overlay_info_card_teaser"),
|
|
||||||
)
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.ad.infocardsuggestions.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
|
||||||
import app.revanced.patches.youtube.ad.infocardsuggestions.annotations.HideInfocardSuggestionsCompatibility
|
|
||||||
import app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints.HideInfocardSuggestionsFingerprint
|
|
||||||
import app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints.HideInfocardSuggestionsParentFingerprint
|
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
|
|
||||||
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
|
||||||
@Name("hide-infocard-suggestions")
|
|
||||||
@Description("Hides infocards in videos.")
|
|
||||||
@HideInfocardSuggestionsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class HideInfocardSuggestionsPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
HideInfocardSuggestionsParentFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
|
||||||
SettingsPatch.PreferenceScreen.ADS.addPreferences(
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_info_cards_enabled",
|
|
||||||
StringResource("revanced_info_cards_enabled_title", "Show info-cards"),
|
|
||||||
false,
|
|
||||||
StringResource("revanced_info_cards_enabled_summary_on", "Info-cards are shown"),
|
|
||||||
StringResource("revanced_info_cards_enabled_summary_off", "Info-cards are hidden")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val parentResult = HideInfocardSuggestionsParentFingerprint.result
|
|
||||||
?: return PatchResultError("Parent fingerprint not resolved!")
|
|
||||||
|
|
||||||
|
|
||||||
HideInfocardSuggestionsFingerprint.resolve(data, parentResult.classDef)
|
|
||||||
val result = HideInfocardSuggestionsFingerprint.result
|
|
||||||
?: return PatchResultError("Required parent method could not be found.")
|
|
||||||
|
|
||||||
val method = result.mutableMethod
|
|
||||||
val implementation = method.implementation
|
|
||||||
?: return PatchResultError("Implementation not found.")
|
|
||||||
|
|
||||||
val index = implementation.instructions.indexOfFirst { ((it as? BuilderInstruction35c)?.reference.toString() == "Landroid/view/View;->setVisibility(I)V") }
|
|
||||||
|
|
||||||
method.replaceInstruction(index, """
|
|
||||||
invoke-static {p1}, Lapp/revanced/integrations/patches/HideInfoCardSuggestionsPatch;->hideInfoCardSuggestions(Landroid/view/View;)V
|
|
||||||
""")
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35", "17.33.42")
|
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.ad.video.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
@Name("show-video-ads-method-fingerprint")
|
|
||||||
@MatchingMethod(
|
|
||||||
definingClass = "zai"
|
|
||||||
)
|
|
||||||
@DirectPatternScanMethod
|
|
||||||
@VideoAdsCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
object ShowVideoAdsFingerprint : MethodFingerprint(
|
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z")
|
|
||||||
)
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user