Compare commits

..

7 Commits

Author SHA1 Message Date
semantic-release-bot
543464f159 chore(release): 2.58.0 [skip ci]
# [2.58.0](https://github.com/oSumAtrIX/revanced-patches/compare/v2.57.0...v2.58.0) (2022-09-17)

### Features

* migrate to `osumatrix/revanced-patcher` dependency ([d20a2d9](331107288d))
2022-09-17 02:31:44 +00:00
oSumAtrIX
de2f9c9d83 build: bump patcher dependency version
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-17 04:28:44 +02:00
oSumAtrIX
b2bca0167a refactor(custom-branding): use getValue operator for options
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-17 04:26:29 +02:00
oSumAtrIX
2f1fef0449 Merge remote-tracking branch 'revanced/main'
# Conflicts:
#	src/main/kotlin/app/revanced/patches/youtube/layout/amoled/patch/AmoledPatch.kt
#	src/main/kotlin/app/revanced/patches/youtube/layout/customthemes/patch/CustomThemePatch.kt
2022-09-17 04:20:49 +02:00
oSumAtrIX
5a058ebcf1 docs: add missing section for patches [skip ci]
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-13 21:36:56 +02:00
oSumAtrIX
011f413088 docs: add differences section in README
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-13 21:36:56 +02:00
oSumAtrIX
331107288d feat: migrate to osumatrix/revanced-patcher dependency
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-13 21:36:44 +02:00
573 changed files with 4876 additions and 18300 deletions

View File

@@ -59,15 +59,3 @@ body:
description: Add additional context here. description: Add additional context here.
validations: validations:
required: false required: false
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you haven't done these steps.
options:
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true

View File

@@ -27,15 +27,3 @@ body:
description: Why should your patch request should be considered? What makes it valuable to the community? description: Why should your patch request should be considered? What makes it valuable to the community?
validations: validations:
required: true required: true
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you haven't done these steps.
options:
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true

View File

@@ -1,25 +0,0 @@
name: PR to main
on:
push:
branches:
- dev
workflow_dispatch:
env:
MESSAGE: merge branch `${{ github.head_ref || github.ref_name }}` to `main`
jobs:
pull-request:
name: Open pull request
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Open pull request
uses: repo-sync/pull-request@v2
with:
destination_branch: 'main'
pr_title: 'chore: ${{ env.MESSAGE }}'
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
pr_draft: true

View File

@@ -1,5 +1,4 @@
name: Release name: Release
on: on:
workflow_dispatch: workflow_dispatch:
push: push:
@@ -10,43 +9,32 @@ on:
branches: branches:
- main - main
- dev - dev
jobs: jobs:
release: release:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-18.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v2
with: with:
# Make sure the release step uses its own credentials:
# https://github.com/cycjimmy/semantic-release-action#private-packages
persist-credentials: false
fetch-depth: 0 fetch-depth: 0
- name: Setup JDK - name: Setup JDK
uses: actions/setup-java@v3 uses: actions/setup-java@v2
with: with:
java-version: '17' java-version: '17'
distribution: 'zulu' distribution: 'adopt'
cache: gradle cache: gradle
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 'latest'
cache: 'npm'
- name: Setup Android SDK - name: Setup Android SDK
uses: amyu/setup-android@v2 uses: android-actions/setup-android@v2
with:
cache-disabled: false
sdk-version: '33'
build-tools-version: '33.0.1'
- name: Build with Gradle - name: Build with Gradle
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew generateMeta clean --no-daemon run: ./gradlew build clean generateMeta
- name: Install Android build-tools
run: sdkmanager "build-tools;32.0.0"
- name: Setup semantic-release - name: Setup semantic-release
run: npm install semantic-release@19.0.5 @saithodev/semantic-release-backmerge @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin@1.7.4 -D run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
- name: Release - name: Release
env: env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release run: npx semantic-release

3
.gitignore vendored
View File

@@ -118,6 +118,3 @@ gradle-app.setting
# Ignore vscode config # Ignore vscode config
.vscode/ .vscode/
# Dependency directories
node_modules/

View File

@@ -7,7 +7,11 @@
} }
], ],
"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", "gradle-semantic-release-plugin",
@@ -32,15 +36,7 @@
{ {
"path": "patches.json" "path": "patches.json"
} }
], ]
successComment: false
}
],
[
"@saithodev/semantic-release-backmerge",
{
branches: [{from: "main", to: "dev"}],
clearWorkspace: true
} }
] ]
] ]

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,18 @@
## 🧩 Patches ## 🧩 Patches
The official Patch bundle provided by ReVanced and the community. Patch bundle provided by ReVanced and the community.
> Looking for the JSON variant of this? [Click here](patches.json). ### ⛏ Differences to [revanced/revanced-patches](https://github.com/revanced/revanced-patches)
- Based on [osumatrix/revanced-patcher](https://github.com/osumatrix/revanced-patcher)
- Minor QoL refactoring
- Several additional patches
### 💊 Patches
{{ table }} {{ table }}
## 📝 JSON Format ### 📝 JSON Format
This section explains the JSON format for the [patches.json](patches.json) file. This section explains the JSON format for the [patches.json](patches.json) file.
@@ -18,6 +24,7 @@ The file contains an array of objects, each object representing a patch. The obj
| `description` | The description of the patch. | | `description` | The description of the patch. |
| `version` | The version of the patch. | | `version` | The version of the patch. |
| `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. | | `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. |
| `deprecated` | Whether the patch is deprecated. |
| `options` | An array of options for this patch. | | `options` | An array of options for this patch. |
| `options.key` | The key of the option. | | `options.key` | The key of the option. |
| `options.title` | The title of the option. | | `options.title` | The title of the option. |
@@ -38,6 +45,7 @@ Example:
"description": "Adds the ability to remember the video quality you chose in the video quality flyout.", "description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
"version": "0.0.1", "version": "0.0.1",
"excluded": false, "excluded": false,
"deprecated": false,
"options": [], "options": [],
"dependencies": [ "dependencies": [
"integrations", "integrations",

274
README.md
View File

@@ -1,200 +1,58 @@
## 🧩 Patches ## 🧩 Patches
The official Patch bundle provided by ReVanced and the community. Patch bundle provided by ReVanced and the community.
> Looking for the JSON variant of this? [Click here](patches.json). ### ⛏ Differences to [revanced/revanced-patches](https://github.com/revanced/revanced-patches)
### [📦 `com.google.android.youtube`](https://play.google.com/store/apps/details?id=com.google.android.youtube) - Based on [osumatrix/revanced-patcher](https://github.com/osumatrix/revanced-patcher)
- Minor QoL refactoring
- Several additional patches
### 💊 Patches
### 📦 `com.twitter.android`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `always-autorepeat` | Always repeats the playing video again. | 17.49.37 | | `timeline-ads` | Removes ads from the Twitter timeline. | all |
| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all |
| `comments` | Hides components related to comments. | 17.49.37 |
| `copy-video-url` | Adds buttons in player to copy video links. | 17.49.37 |
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
| `custom-video-buffer` | Lets you change the buffers of videos. | 17.49.37 |
| `custom-video-speed` | Adds more video speed options. | 17.49.37 |
| `debugging` | Adds debugging options. | all |
| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 17.49.37 |
| `disable-auto-player-popup-panels` | Disable automatic popup panels (playlist or live chat) on video player. | 17.49.37 |
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 17.49.37 |
| `disable-startup-shorts-player` | Disables playing YouTube Shorts when launching YouTube. | 17.49.37 |
| `disable-zoom-haptics` | Disables haptics when zooming. | all |
| `downloads` | Enables downloading music and videos from YouTube. | 17.49.37 |
| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 17.49.37 |
| `general-ads` | Removes general ads. | 17.49.37 |
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.49.37 |
| `hide-album-cards` | Hides the album cards below the artist description. | 17.49.37 |
| `hide-artist-card` | Hides the artist card below the searchbar. | 17.49.37 |
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.49.37 |
| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 17.49.37 |
| `hide-captions-button` | Hides the captions button on video player. | 17.49.37 |
| `hide-cast-button` | Hides the cast button in the video player. | all |
| `hide-create-button` | Hides the create button in the navigation bar. | 17.49.37 |
| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 17.49.37 |
| `hide-email-address` | Hides the email address in the account switcher. | 17.49.37 |
| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 17.49.37 |
| `hide-info-cards` | Hides info-cards in videos. | 17.49.37 |
| `hide-my-mix` | Hides mix playlists. | 17.49.37 |
| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 17.49.37 |
| `hide-time-and-seekbar` | Hides progress bar and time counter on videos. | 17.49.37 |
| `hide-video-buttons` | Adds options to hide action buttons under a video. | 17.49.37 |
| `hide-watch-in-vr` | Hides the Watch in VR option in the player settings flyout panel. | 17.49.37 |
| `hide-watermark` | Hides creator's watermarks on videos. | 17.49.37 |
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 17.49.37 |
| `minimized-playback` | Enables minimized and background playback. | 17.49.37 |
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 17.49.37 |
| `open-links-directly` | Bypasses https://youtube.com/redirect URLs. | 17.49.37 |
| `premium-heading` | Shows premium branding on the home screen. | all |
| `remember-playback-rate` | Adds the ability to remember the playback rate you chose in the video playback rate flyout. | 17.49.37 |
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 17.49.37 |
| `remove-player-button-background` | Removes the background from the video player buttons. | 17.49.37 |
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 17.49.37 |
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.49.37 |
| `settings` | Adds settings for ReVanced to YouTube. | all |
| `sponsorblock` | Integrate SponsorBlock. | 17.49.37 |
| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 17.49.37 |
| `swipe-controls` | Adds volume and brightness swipe controls. | 17.49.37 |
| `tablet-mini-player` | Enables the tablet mini player layout. | 17.49.37 |
| `theme` | Applies a custom theme. | all |
| `video-ads` | Removes ads in the video player. | 17.49.37 |
</details> </details>
### [📦 `com.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music) ### 📦 `com.reddit.frontpage`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `background-play` | Enables playing music in the background. | 5.39.52 | | `premium-icon-reddit` | Unlocking Premium Icons in reddit app. | all |
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.39.52 | | `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | all |
| `compact-header` | Hides the music category bar at the top of the homepage. | 5.39.52 |
| `exclusive-audio-playback` | Enables the option to play music without video. | 5.39.52 |
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.39.52 |
| `minimized-playback-music` | Enables minimized playback on Kids music. | 5.39.52 |
| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | 5.39.52 |
| `music-video-ads` | Removes ads in the music player. | 5.39.52 |
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.39.52 |
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.39.52 |
</details> </details>
### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill) ### 📦 `com.garzotto.pflotsh.ecmwf_a`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `disable-login-requirement` | Do not force login. | all | | `pflotsh-ecmwf-subscription-unlock` | Unlocks all subscription features. | 3.5.4 |
| `downloads` | Removes download restrictions and changes the default path to download to. | 27.8.3 |
| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | 27.8.3 |
| `fix-google-login` | Allows logging in with a Google account. | all |
| `hide-ads` | Removes ads from TikTok. | all |
| `playback-speed` | Enables the playback speed option for all videos. | all |
| `settings` | Adds ReVanced settings to TikTok. | 27.8.3 |
| `show-seekbar` | Shows progress bar for all video. | all |
| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | 27.8.3 |
</details> </details>
### [📦 `com.zhiliaoapp.musically`](https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically) ### 📦 `com.google.android.apps.youtube.music`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `disable-login-requirement` | Do not force login. | all | | `minimized-playback-music` | Enables minimized playback on Kids music. | 5.23.50 |
| `downloads` | Removes download restrictions and changes the default path to download to. | 27.8.3 | | `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.23.50 |
| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | 27.8.3 | | `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.23.50 |
| `fix-google-login` | Allows logging in with a Google account. | all | | `compact-header` | Hides the music category bar at the top of the homepage. | 5.23.50 |
| `hide-ads` | Removes ads from TikTok. | all | | `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.23.50 |
| `playback-speed` | Enables the playback speed option for all videos. | all | | `background-play` | Enables playing music in the background. | 5.23.50 |
| `settings` | Adds ReVanced settings to TikTok. | 27.8.3 | | `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | 5.23.50 |
| `show-seekbar` | Shows progress bar for all video. | all | | `music-video-ads` | Removes ads in the music player. | 5.23.50 |
| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | 27.8.3 | | `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.23.50 |
| `exclusive-audio-playback` | Enables the option to play music without video. | 5.23.50 |
</details> </details>
### [📦 `tv.twitch.android.app`](https://play.google.com/store/apps/details?id=tv.twitch.android.app) ### 📦 `de.dwd.warnapp`
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `block-audio-ads` | Blocks audio ads in streams and VODs. | all |
| `block-embedded-ads` | Blocks embedded steam ads using services like TTV.lol or PurpleAdBlocker. | all |
| `block-video-ads` | Blocks video ads in streams and VODs. | all |
| `debug-mode` | Enables Twitch's internal debugging mode. | all |
| `settings` | Adds settings menu to Twitch. | all |
| `show-deleted-messages` | Shows deleted chat messages behind a clickable spoiler. | all |
</details>
### [📦 `com.twitter.android`](https://play.google.com/store/apps/details?id=com.twitter.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `dynamic-color` | Replaces the default Twitter Blue with the users Material You palette. | all |
| `hide-views-stats` | Hides the view stats under tweets. | all |
| `monochrome-icon` | Adds a monochrome icon. | all |
| `timeline-ads` | Removes ads from the Twitter timeline. Might require clearing app data to remove already cached ads. | all |
</details>
### [📦 `com.spotify.music`](https://play.google.com/store/apps/details?id=com.spotify.music)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-capture-restriction` | Allows capturing Spotify's audio output while screen sharing or screen recording. | all |
| `hide-premium-navbar` | Removes the premium tab from the navbar. | all |
| `spotify-theme` | Applies a custom theme. | all |
</details>
### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2022.43.0 |
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
</details>
### [📦 `com.vanced.android.youtube`](https://play.google.com/store/apps/details?id=com.vanced.android.youtube)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all |
</details>
### [📦 `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-ads` | Disables ads in HexEditor. | all |
</details>
### [📦 `org.citra.citra_emu`](https://play.google.com/store/apps/details?id=org.citra.citra_emu)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `premium-unlock` | Unlocks premium functions. | all |
</details>
### [📦 `org.citra.citra_emu.canary`](https://play.google.com/store/apps/details?id=org.citra.citra_emu.canary)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `premium-unlock` | Unlocks premium functions. | all |
</details>
### [📦 `com.backdrops.wallpapers`](https://play.google.com/store/apps/details?id=com.backdrops.wallpapers)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `pro-unlock` | Unlocks pro-only functions. | all |
</details>
### [📦 `de.dwd.warnapp`](https://play.google.com/store/apps/details?id=de.dwd.warnapp)
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
@@ -202,65 +60,75 @@ The official Patch bundle provided by ReVanced and the community.
| `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all | | `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all |
</details> </details>
### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx) ### 📦 `com.ss.android.ugc.trill`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all | | `tiktok-download` | Removes download restrictions and changes the default path to download to. | all |
| `tiktok-seekbar` | Show progress bar for all video. | all |
| `tiktok-ads` | Removes ads from TikTok. | all |
</details> </details>
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android) ### 📦 `com.zhiliaoapp.musically`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all | | `tiktok-download` | Removes download restrictions and changes the default path to download to. | all |
| `tiktok-seekbar` | Show progress bar for all video. | all |
| `tiktok-ads` | Removes ads from TikTok. | all |
</details> </details>
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio) ### 📦 `com.google.android.youtube`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all | | `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 |
| `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 |
| `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 |
| `custom-theme` | Applies a custom theme. | all |
| `tablet-mini-player` | Enables the tablet mini player layout. | 17.33.42 |
| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 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> </details>
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses) ### 📦 `com.vanced.android.youtube`
<details> <details>
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all professional features. | all | | `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all |
</details>
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-themes` | Unlocks all themes. | all |
</details>
### [📦 `net.dinglisch.android.taskerm`](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-trial` | Unlocks the trial version. | all |
</details> </details>
## 📝 JSON Format ### 📝 JSON Format
This section explains the JSON format for the [patches.json](patches.json) file. This section explains the JSON format for the [patches.json](patches.json) file.
@@ -272,6 +140,7 @@ The file contains an array of objects, each object representing a patch. The obj
| `description` | The description of the patch. | | `description` | The description of the patch. |
| `version` | The version of the patch. | | `version` | The version of the patch. |
| `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. | | `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. |
| `deprecated` | Whether the patch is deprecated. |
| `options` | An array of options for this patch. | | `options` | An array of options for this patch. |
| `options.key` | The key of the option. | | `options.key` | The key of the option. |
| `options.title` | The title of the option. | | `options.title` | The title of the option. |
@@ -292,6 +161,7 @@ Example:
"description": "Adds the ability to remember the video quality you chose in the video quality flyout.", "description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
"version": "0.0.1", "version": "0.0.1",
"excluded": false, "excluded": false,
"deprecated": false,
"options": [], "options": [],
"dependencies": [ "dependencies": [
"integrations", "integrations",

View File

@@ -11,7 +11,14 @@ repositories {
mavenCentral() mavenCentral()
mavenLocal() mavenLocal()
maven { maven {
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") url = uri("https://maven.pkg.github.com/osumatrix/revanced-patcher")
credentials {
username = githubUsername
password = githubPassword
}
}
maven {
url = uri("https://maven.pkg.github.com/revanced/multidexlib2")
credentials { credentials {
username = githubUsername username = githubUsername
password = githubPassword password = githubPassword
@@ -20,10 +27,11 @@ repositories {
} }
dependencies { dependencies {
implementation("app.revanced:revanced-patcher:6.4.1") implementation("app.revanced:revanced-patcher:4.5.0")
implementation("app.revanced:multidexlib2:2.5.2.r2") implementation("app.revanced:multidexlib2:2.5.2.r2")
// Required for meta // Required for meta
implementation("com.google.code.gson:gson:2.10") implementation("com.google.code.gson:gson:2.9.1")
} }
tasks { tasks {
@@ -33,7 +41,7 @@ tasks {
doLast { doLast {
val androidHome = System.getenv("ANDROID_HOME") ?: throw GradleException("ANDROID_HOME not found") val androidHome = System.getenv("ANDROID_HOME") ?: throw GradleException("ANDROID_HOME not found")
val d8 = "${androidHome}/build-tools/33.0.1/d8" val d8 = "${androidHome}/build-tools/32.0.0/d8"
val input = configurations.archives.get().allArtifacts.files.files.first().absolutePath val input = configurations.archives.get().allArtifacts.files.files.first().absolutePath
val work = File("${buildDir}/libs") val work = File("${buildDir}/libs")

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 2.155.1-dev.1 version = 2.58.0

6107
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +0,0 @@
{
"devDependencies": {
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.7.4",
"semantic-release": "^19.0.5"
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,30 +1,45 @@
package app.revanced.extensions package app.revanced.extensions
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.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.iface.Method import app.revanced.patcher.util.smali.toInstruction
import org.jf.dexlib2.util.MethodUtil import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
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: populate this to all patches // TODO: this method does not make sense here
/** internal fun MutableMethodImplementation.injectHideCall(
* Convert a [MethodFingerprint] to a [PatchResultError]. index: Int,
* register: Int
* @return A [PatchResultError] for the [MethodFingerprint]. ) {
*/ this.addInstruction(
fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $name") index,
"invoke-static { v$register }, Lapp/revanced/integrations/patches/HideHomeAdsPatch;->HideHomeAds(Landroid/view/View;)V".toInstruction()
)
}
/** /**
* Find the [MutableMethod] from a given [Method] in a [MutableClass]. * traverse the class hierarchy starting from the given root class
* *
* @param method The [Method] to find. * @param targetClass the class to start traversing the class hierarchy from
* @return The [MutableMethod]. * @param callback function that is called for every class in the hierarchy
*/ */
fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { fun BytecodeData.traverseClassHierarchy(targetClass: MutableClass, callback: MutableClass.() -> Unit) {
MethodUtil.methodSignaturesMatch(it, method) callback(targetClass)
this.findClass(targetClass.superclass ?: return)?.resolve()?.let {
traverseClassHierarchy(it, callback)
}
} }
/** /**
@@ -38,7 +53,160 @@ fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod)
methods.addAll(transformedMethods) 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)
} }
internal fun String.startsWithAny(vararg prefixes: String): Boolean {
for (prefix in prefixes)
if (this.startsWith(prefix))
return true
return false
}
internal fun String.equalsAny(vararg other: String): Boolean {
for (_other in other)
if (this == _other)
return true
return false
}

View File

@@ -2,12 +2,12 @@ package app.revanced.meta
import app.revanced.meta.json.generateJson import app.revanced.meta.json.generateJson
import app.revanced.meta.readme.generateText import app.revanced.meta.readme.generateText
import app.revanced.patcher.data.Context import app.revanced.patcher.data.Data
import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.Patch
import app.revanced.patcher.util.patch.PatchBundle import app.revanced.patcher.util.patch.impl.JarPatchBundle
import java.io.File import java.io.File
typealias Bundle = List<Class<out Patch<Context>>> typealias Bundle = List<Class<out Patch<Data>>>
object Meta { object Meta {
@JvmStatic @JvmStatic
@@ -20,7 +20,7 @@ object Meta {
} }
} }
fun accumulatePatches() = PatchBundle.Jar( fun accumulatePatches() = JarPatchBundle(
File("build/libs/").listFiles()!!.first { File("build/libs/").listFiles()!!.first {
it.name.startsWith("revanced-patches-") && it.name.endsWith(".jar") it.name.startsWith("revanced-patches-") && it.name.endsWith(".jar")
}.absolutePath }.absolutePath

View File

@@ -3,6 +3,7 @@ package app.revanced.meta.json
import app.revanced.meta.Bundle import app.revanced.meta.Bundle
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.dependencies import app.revanced.patcher.extensions.PatchExtensions.dependencies
import app.revanced.patcher.extensions.PatchExtensions.deprecated
import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.include import app.revanced.patcher.extensions.PatchExtensions.include
import app.revanced.patcher.extensions.PatchExtensions.options import app.revanced.patcher.extensions.PatchExtensions.options
@@ -21,6 +22,7 @@ fun generateJson(bundle: Bundle) {
it.description ?: "This patch has no description.", it.description ?: "This patch has no description.",
it.version ?: "0.0.0", it.version ?: "0.0.0",
!it.include, !it.include,
it.deprecated != null,
it.options?.map { option -> it.options?.map { option ->
Option( Option(
option.key, option.key,

View File

@@ -7,6 +7,7 @@ data class JsonPatch(
val description: String, val description: String,
val version: String, val version: String,
val excluded: Boolean, val excluded: Boolean,
val deprecated: Boolean,
val options: Array<Option>, val options: Array<Option>,
val dependencies: Array<String>, val dependencies: Array<String>,
val compatiblePackages: Array<CompatiblePackage>, val compatiblePackages: Array<CompatiblePackage>,

View File

@@ -1,10 +1,10 @@
package app.revanced.meta.readme package app.revanced.meta.readme
import app.revanced.patcher.data.Context import app.revanced.patcher.data.Data
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.Patch
internal fun Class<out Patch<Context>>.getLatestVersion() = internal fun Class<out Patch<Data>>.getLatestVersion() =
this.compatiblePackages?.first()?.versions?.map { this.compatiblePackages?.first()?.versions?.map {
SemanticVersion.fromString(it) SemanticVersion.fromString(it)
}?.maxWithOrNull(SemanticVersionComparator) }?.maxWithOrNull(SemanticVersionComparator)

View File

@@ -1,7 +1,7 @@
package app.revanced.meta.readme package app.revanced.meta.readme
import app.revanced.meta.Bundle import app.revanced.meta.Bundle
import app.revanced.patcher.data.Context import app.revanced.patcher.data.Data
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.PatchExtensions.patchName
@@ -15,7 +15,7 @@ private val TABLE_REGEX = Regex("\\{\\{\\s?table\\s?}}")
fun generateText(bundle: Bundle) { fun generateText(bundle: Bundle) {
val output = StringBuilder() val output = StringBuilder()
val packages = mutableMapOf<String, MutableList<Class<out Patch<Context>>>>() val packages = mutableMapOf<String, MutableList<Class<out Patch<Data>>>>()
for (patch in bundle) { for (patch in bundle) {
patch.compatiblePackages?.forEach { pkg -> patch.compatiblePackages?.forEach { pkg ->
@@ -24,8 +24,8 @@ fun generateText(bundle: Bundle) {
} }
} }
for (pkg in packages.entries.sortedByDescending { it.value.size }) { for (pkg in packages) {
output.appendLine("### [\uD83D\uDCE6 `${pkg.key}`](https://play.google.com/store/apps/details?id=${pkg.key})") output.appendLine("### \uD83D\uDCE6 `${pkg.key}`")
output.appendLine("<details>\n") output.appendLine("<details>\n")
output.appendLine(TABLE_HEADER) output.appendLine(TABLE_HEADER)

View File

@@ -1,37 +0,0 @@
package app.revanced.patches.all.interaction.gestures.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.Patch
@Patch(false)
@Name("predictive-back-gesture")
@Description("Enables the predictive back gesture introduced on Android 13.")
@Version("0.0.1")
class PredictiveBackGesturePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
with(document.getElementsByTagName("application").item(0)) {
if (attributes.getNamedItem(FLAG) != null) return@with
document.createAttribute(FLAG)
.apply { value = "true" }
.let(attributes::setNamedItem)
}
}
return PatchResultSuccess()
}
private companion object {
const val FLAG = "android:enableOnBackInvokedCallback"
}
}

View File

@@ -1,106 +0,0 @@
package app.revanced.patches.all.screenshot.removerestriction.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.iface.reference.MethodReference
@Patch(false)
@Name("remove-screenshot-restriction")
@Description("Removes the restriction of making screenshots.")
@Version("0.0.1")
class RemoveScreenshotRestrictionPatch : BytecodePatch() {
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch;"
}
// Information about method calls we want to replace
private enum class MethodCall(
val definedClassName: String,
val methodName: String,
val replacementMethodDefinition: String
) {
SetFlags(
"Landroid/view/Window;",
"setFlags",
"setFlags(Landroid/view/Window;II)V",
);
fun replaceInstruction(method: MutableMethod, instruction: Instruction35c, instructionIndex: Int) {
when (this) {
SetFlags -> {
method.replaceInstruction(
instructionIndex,
"invoke-static { v${instruction.registerC}, v${instruction.registerD}, v${instruction.registerE} }, ${INTEGRATIONS_CLASS_DESCRIPTOR}->${replacementMethodDefinition}"
)
}
}
}
companion object {
fun fromMethodReference(methodReference: MethodReference) = values().firstOrNull { search ->
search.definedClassName == methodReference.definingClass && search.methodName == methodReference.name
}
}
}
override fun execute(context: BytecodeContext): PatchResult {
// Find all instructions where one of the methods is called
buildMap {
context.classes.forEach { classDef ->
if (classDef.type == INTEGRATIONS_CLASS_DESCRIPTOR) {
// avoid infinite recursion
return@forEach
}
classDef.methods.let { methods ->
buildMap methodList@{
methods.forEach methods@{ method ->
with(method.implementation?.instructions ?: return@methods) {
ArrayDeque<Triple<MethodCall, Instruction35c, Int>>().also { patchIndices ->
this.forEachIndexed { index, instruction ->
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
val invokeInstruction = instruction as Instruction35c
val methodRef = invokeInstruction.reference as MethodReference
val methodCall = MethodCall.fromMethodReference(methodRef) ?: return@forEachIndexed
patchIndices.add(Triple(methodCall, invokeInstruction, index))
}
}.also { if (it.isEmpty()) return@methods }.let { patches ->
put(method, patches)
}
}
}
}
}.also { if (it.isEmpty()) return@forEach }.let { methodPatches ->
put(classDef, methodPatches)
}
}
}.forEach { (classDef, methods) ->
// And finally replace the instructions...
with(context.proxy(classDef).mutableClass) {
methods.forEach { (method, patches) ->
val mutableMethod = findMutableMethodOf(method)
while (!patches.isEmpty()) {
val (methodType, instruction, instructionIndex) = patches.removeLast()
methodType.replaceInstruction(mutableMethod, instruction, instructionIndex)
}
}
}
}
return PatchResultSuccess()
}
}

View File

@@ -1,7 +0,0 @@
package app.revanced.patches.backdrops.misc.pro.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.backdrops.wallpapers")])
internal annotation class ProUnlockCompatibility

View File

@@ -1,15 +0,0 @@
package app.revanced.patches.backdrops.misc.pro.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object ProUnlockFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ
),
customFingerprint = { it.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;" && it.name == "lambda\$existPurchase\$0" }
)

View File

@@ -1,42 +0,0 @@
package app.revanced.patches.backdrops.misc.pro.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
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.patches.backdrops.misc.pro.annotations.ProUnlockCompatibility
import app.revanced.patches.backdrops.misc.pro.fingerprints.ProUnlockFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("pro-unlock")
@Description("Unlocks pro-only functions.")
@ProUnlockCompatibility
@Version("0.0.1")
class ProUnlockPatch : BytecodePatch(
listOf(ProUnlockFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = ProUnlockFingerprint.result ?: return PatchResultError("${ProUnlockFingerprint.name} not found")
val moveRegisterInstruction = result.mutableMethod.instruction(result.scanResult.patternScanResult!!.endIndex - 1)
val register = (moveRegisterInstruction as OneRegisterInstruction).registerA
result.mutableMethod.addInstructions(
result.scanResult.patternScanResult!!.endIndex,
"""
const/4 v$register, 0x1
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,7 +0,0 @@
package app.revanced.patches.citra.misc.premium.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("org.citra.citra_emu"), Package("org.citra.citra_emu.canary")])
internal annotation class PremiumUnlockCompatbility

View File

@@ -1,7 +0,0 @@
package app.revanced.patches.citra.misc.premium.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PremiumUnlockFingerprint : MethodFingerprint(
customFingerprint = { it.definingClass == "Lorg/citra/citra_emu/ui/main/MainActivity;" && it.name == "isPremiumActive" }
)

View File

@@ -1,37 +0,0 @@
package app.revanced.patches.citra.misc.premium.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
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.patches.citra.misc.premium.annotations.PremiumUnlockCompatbility
import app.revanced.patches.citra.misc.premium.fingerprints.PremiumUnlockFingerprint
@Patch
@Name("premium-unlock")
@Description("Unlocks premium functions.")
@PremiumUnlockCompatbility
@Version("0.0.1")
class PremiumUnlockPatch : BytecodePatch(
listOf(PremiumUnlockFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = PremiumUnlockFingerprint.result ?: return PatchResultError("${PremiumUnlockFingerprint.name} not found")
result.mutableMethod.addInstructions(
0,
"""
const v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,13 +0,0 @@
package app.revanced.patches.hexeditor.ad.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[
Package("com.myprog.hexedit")
]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class HexEditorAdsCompatibility

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.hexeditor.ad.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PrimaryAdsFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("PreferencesHelper;") && methodDef.name == "isAdsDisabled"
}
)

View File

@@ -1,39 +0,0 @@
package app.revanced.patches.hexeditor.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.BytecodeContext
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.hexeditor.ad.annotations.HexEditorAdsCompatibility
import app.revanced.patches.hexeditor.ad.fingerprints.PrimaryAdsFingerprint
@Patch
@Name("disable-ads")
@Description("Disables ads in HexEditor.")
@HexEditorAdsCompatibility
@Version("0.0.1")
class HexEditorAdsPatch : BytecodePatch(
listOf(
PrimaryAdsFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val method = PrimaryAdsFingerprint.result!!.mutableMethod
method.replaceInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.iconpackstudio.misc.pro.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("ginlemon.iconpackstudio")])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class UnlockProCompatibility

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.iconpackstudio.misc.pro.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object CheckProFingerprint : MethodFingerprint(
"Z",
customFingerprint = { it.definingClass.endsWith("IPSPurchaseRepository;")}
)

View File

@@ -1,38 +0,0 @@
package app.revanced.patches.iconpackstudio.misc.pro.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.iconpackstudio.misc.pro.annotations.UnlockProCompatibility
import app.revanced.patches.iconpackstudio.misc.pro.fingerprints.CheckProFingerprint
@Patch
@Name("unlock-pro")
@Description("Unlocks all pro features.")
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProPatch : BytecodePatch(
listOf(
CheckProFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val method = CheckProFingerprint.result!!.mutableMethod
method.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.moneymanager.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.ithebk.expensemanager")])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class UnlockProCompatibility

View File

@@ -1,19 +0,0 @@
package app.revanced.patches.moneymanager.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object UnlockProFingerprint : MethodFingerprint(
"Z",
AccessFlags.STATIC or AccessFlags.SYNTHETIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET_BOOLEAN,
Opcode.RETURN
),
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("MainActivity;")
}
)

View File

@@ -1,34 +0,0 @@
package app.revanced.patches.moneymanager.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.moneymanager.annotations.UnlockProCompatibility
import app.revanced.patches.moneymanager.fingerprints.UnlockProFingerprint
@Patch
@Name("unlock-pro")
@Description("Unlocks pro features.")
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProPatch : BytecodePatch(
listOf(UnlockProFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
UnlockProFingerprint.result!!.mutableMethod.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,11 +1,23 @@
package app.revanced.patches.music.ad.video.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint 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.AccessFlags
import org.jf.dexlib2.Opcode 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. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@MusicVideoAdsCompatibility
@Version("0.0.1")
object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint( object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,

View File

@@ -1,10 +1,22 @@
package app.revanced.patches.music.ad.video.fingerprints 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.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.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode 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( object ShowMusicVideoAdsFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf(
Opcode.IPUT_BOOLEAN, Opcode.IPUT_BOOLEAN,

View File

@@ -3,13 +3,13 @@ package app.revanced.patches.music.ad.video.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess 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.patches.music.ad.video.annotations.MusicVideoAdsCompatibility 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.ShowMusicVideoAdsConstructorFingerprint
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint
@@ -24,13 +24,13 @@ class MusicVideoAdsPatch : BytecodePatch(
ShowMusicVideoAdsConstructorFingerprint ShowMusicVideoAdsConstructorFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef) ShowMusicVideoAdsFingerprint.resolve(data, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef)
val result = ShowMusicVideoAdsFingerprint.result!! val result = ShowMusicVideoAdsFingerprint.result!!
result.mutableMethod.addInstructions( result.mutableMethod.addInstructions(
result.scanResult.patternScanResult!!.startIndex, """ result.patternScanResult!!.startIndex, """
const/4 p1, 0x0 const/4 p1, 0x0
""" """
) )

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,13 +1,23 @@
package app.revanced.patches.music.audio.codecs.fingerprints package app.revanced.patches.music.audio.codecs.fingerprints
import app.revanced.patcher.annotation.Name
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.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
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")
@MatchingMethod(
"Laari;",
"b",
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@CodecsUnlockCompatibility
@Version("0.0.1")
object AllCodecsReferenceFingerprint : MethodFingerprint( object AllCodecsReferenceFingerprint : MethodFingerprint(
"J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( "J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,

View File

@@ -1,13 +1,23 @@
package app.revanced.patches.music.audio.codecs.fingerprints package app.revanced.patches.music.audio.codecs.fingerprints
import app.revanced.patcher.annotation.Name
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.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
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")
@MatchingMethod(
"Lacfr;",
"a",
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@CodecsUnlockCompatibility
@Version("0.0.1")
object CodecsLockFingerprint : MethodFingerprint( object CodecsLockFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( "L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,
@@ -22,7 +32,7 @@ object CodecsLockFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_DIRECT,
Opcode.RETURN_OBJECT Opcode.RETURN_OBJECT
), ),
strings = listOf("eac3_supported") strings = listOf("eac3_supported")

View File

@@ -3,12 +3,12 @@ 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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.data.impl.toMethodWalker
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
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.fingerprints.AllCodecsReferenceFingerprint
@@ -25,12 +25,12 @@ class CodecsUnlockPatch : BytecodePatch(
CodecsLockFingerprint, AllCodecsReferenceFingerprint CodecsLockFingerprint, AllCodecsReferenceFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val codecsLockResult = CodecsLockFingerprint.result!! val codecsLockResult = CodecsLockFingerprint.result!!
val implementation = codecsLockResult.mutableMethod.implementation!! val implementation = codecsLockResult.mutableMethod.implementation!!
val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex val scanResultStartIndex = codecsLockResult.patternScanResult!!.startIndex
val instructionIndex = scanResultStartIndex + val instructionIndex = scanResultStartIndex +
if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) { if (implementation.instructions[scanResultStartIndex - 1].opcode == Opcode.CHECK_CAST) {
// for 5.16.xx and lower // for 5.16.xx and lower
@@ -42,8 +42,8 @@ class CodecsUnlockPatch : BytecodePatch(
val allCodecsResult = AllCodecsReferenceFingerprint.result!! val allCodecsResult = AllCodecsReferenceFingerprint.result!!
val allCodecsMethod = val allCodecsMethod =
context.toMethodWalker(allCodecsResult.method) data.toMethodWalker(allCodecsResult.method)
.nextMethod(allCodecsResult.scanResult.patternScanResult!!.startIndex) .nextMethod(allCodecsResult.patternScanResult!!.startIndex)
.getMethod() .getMethod()
implementation.replaceInstruction( implementation.replaceInstruction(

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,10 +1,25 @@
package app.revanced.patches.music.audio.exclusiveaudio.fingerprints 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.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.patcher.fingerprint.method.impl.MethodFingerprint
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("audio-only-enabler-fingerprint")
@MatchingMethod(
"Lgmd;",
"d"
)
@DirectPatternScanMethod
@ExclusiveAudioCompatibility
@Version(
"0.0.1"
)
object AudioOnlyEnablerFingerprint: MethodFingerprint( object AudioOnlyEnablerFingerprint: MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( "Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,

View File

@@ -1,13 +1,22 @@
package app.revanced.patches.music.audio.exclusiveaudio.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint 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.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")
@MatchingMethod(
"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
@Version("0.0.1")
object ExclusiveAudioFingerprint : MethodFingerprint( object ExclusiveAudioFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, AccessFlags.PUBLIC or AccessFlags.FINAL,

View File

@@ -3,15 +3,17 @@ 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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess 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.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.fingerprints.AudioOnlyEnablerFingerprint
import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.ExclusiveAudioFingerprint
@Patch @Patch
@Name("exclusive-audio-playback") @Name("exclusive-audio-playback")
@@ -23,7 +25,7 @@ class ExclusiveAudioPatch : BytecodePatch(
AudioOnlyEnablerFingerprint AudioOnlyEnablerFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val method = AudioOnlyEnablerFingerprint.result!!.mutableMethod val method = AudioOnlyEnablerFingerprint.result!!.mutableMethod
method.replaceInstruction(method.implementation!!.instructions.count() - 1, "const/4 v0, 0x1") method.replaceInstruction(method.implementation!!.instructions.count() - 1, "const/4 v0, 0x1")
method.addInstruction("return v0") method.addInstruction("return v0")

View File

@@ -5,25 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,10 +1,20 @@
package app.revanced.patches.music.layout.compactheader.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint 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.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@Name("compact-header-constructor-fingerprint")
@MatchingMethod(
"Llcz;", "<init>"
)
@CompactHeaderCompatibility
@Version("0.0.1")
object CompactHeaderConstructorFingerprint : MethodFingerprint( object CompactHeaderConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,

View File

@@ -3,12 +3,12 @@ package app.revanced.patches.music.layout.compactheader.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.layout.compactheader.annotations.CompactHeaderCompatibility import app.revanced.patches.music.layout.compactheader.annotations.CompactHeaderCompatibility
import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
@@ -23,11 +23,11 @@ class CompactHeaderPatch : BytecodePatch(
CompactHeaderConstructorFingerprint CompactHeaderConstructorFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val result = CompactHeaderConstructorFingerprint.result!! val result = CompactHeaderConstructorFingerprint.result!!
val method = result.mutableMethod val method = result.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex val insertIndex = result.patternScanResult!!.endIndex
val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA
method.addInstructions( method.addInstructions(
insertIndex, """ insertIndex, """

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,10 +1,20 @@
package app.revanced.patches.music.layout.minimizedplayback.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint 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.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@Name("minimized-playback-manager-fingerprint")
@MatchingMethod(
"Llxw;", "c"
)
@MinimizedPlaybackCompatibility
@Version("0.0.1")
object MinimizedPlaybackManagerFingerprint : MethodFingerprint( object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, AccessFlags.PUBLIC or AccessFlags.FINAL,

View File

@@ -3,14 +3,18 @@ package app.revanced.patches.music.layout.minimizedplayback.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.data.impl.toMethodWalker
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess 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.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.music.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility import app.revanced.patches.music.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@Patch @Patch
@Name("minimized-playback-music") @Name("minimized-playback-music")
@@ -22,7 +26,7 @@ class MinimizedPlaybackPatch : BytecodePatch(
MinimizedPlaybackManagerFingerprint MinimizedPlaybackManagerFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions( MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions(
0, """ 0, """
return-void return-void

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,10 +1,20 @@
package app.revanced.patches.music.layout.premium.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint 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.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@Name("hide-get-premium-fingerprint")
@MatchingMethod(
"Lktn;", "k"
)
@HideGetPremiumCompatibility
@Version("0.0.1")
object HideGetPremiumFingerprint : MethodFingerprint( object HideGetPremiumFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
Opcode.IF_NEZ, Opcode.IF_NEZ,

View File

@@ -1,10 +1,20 @@
package app.revanced.patches.music.layout.premium.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint 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.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@Name("hide-get-premium-parent-fingerprint")
@MatchingMethod(
"Lktn;", "k"
)
@HideGetPremiumCompatibility
@Version("0.0.1")
object HideGetPremiumParentFingerprint : MethodFingerprint( object HideGetPremiumParentFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
Opcode.IGET_BOOLEAN, Opcode.IGET_BOOLEAN,

View File

@@ -3,14 +3,14 @@ package app.revanced.patches.music.layout.premium.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.layout.premium.annotations.HideGetPremiumCompatibility 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.HideGetPremiumFingerprint
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint
@@ -25,15 +25,13 @@ class HideGetPremiumPatch : BytecodePatch(
HideGetPremiumParentFingerprint HideGetPremiumParentFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val parentResult = HideGetPremiumParentFingerprint.result!! val parentResult = HideGetPremiumParentFingerprint.result!!
HideGetPremiumFingerprint.resolve(context, parentResult.classDef) HideGetPremiumFingerprint.resolve(data, parentResult.classDef)
val startIndex = parentResult.scanResult.patternScanResult!!.startIndex
val parentMethod = parentResult.mutableMethod val parentMethod = parentResult.mutableMethod
parentMethod.replaceInstruction( parentMethod.replaceInstruction(
startIndex, """ parentResult.patternScanResult!!.startIndex, """
const/4 v1, 0x0 const/4 v1, 0x0
""" """
) )
@@ -41,7 +39,7 @@ class HideGetPremiumPatch : BytecodePatch(
val result = HideGetPremiumFingerprint.result!! val result = HideGetPremiumFingerprint.result!!
val method = result.mutableMethod val method = result.mutableMethod
method.addInstructions( method.addInstructions(
startIndex, """ result.patternScanResult!!.startIndex, """
const/16 v0, 0x8 const/16 v0, 0x8
""" """
) )

View File

@@ -10,23 +10,7 @@ import app.revanced.patcher.annotation.Package
*/ */
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,13 +1,22 @@
package app.revanced.patches.music.layout.tastebuilder.fingerprints package app.revanced.patches.music.layout.tastebuilder.fingerprints
import app.revanced.patcher.annotation.Name
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.fingerprint.method.impl.MethodFingerprint 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.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")
@MatchingMethod(
"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
@Version("0.0.1")
object TasteBuilderConstructorFingerprint : MethodFingerprint( object TasteBuilderConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,

View File

@@ -3,12 +3,12 @@ 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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
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.fingerprints.TasteBuilderConstructorFingerprint
import org.jf.dexlib2.iface.instruction.formats.Instruction22c import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@@ -23,11 +23,11 @@ class RemoveTasteBuilderPatch : BytecodePatch(
TasteBuilderConstructorFingerprint TasteBuilderConstructorFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val result = TasteBuilderConstructorFingerprint.result!! val result = TasteBuilderConstructorFingerprint.result!!
val method = result.mutableMethod val method = result.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex - 8 val insertIndex = result.patternScanResult!!.endIndex - 8
val register = (method.implementation!!.instructions[insertIndex] as Instruction22c).registerA val register = (method.implementation!!.instructions[insertIndex] as Instruction22c).registerA
method.addInstructions( method.addInstructions(
insertIndex, """ insertIndex, """

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,13 +1,22 @@
package app.revanced.patches.music.layout.upgradebutton.fingerprints package app.revanced.patches.music.layout.upgradebutton.fingerprints
import app.revanced.patcher.annotation.Name
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.fingerprint.method.impl.MethodFingerprint 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.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")
@MatchingMethod(
"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
@Version("0.0.1")
object PivotBarConstructorFingerprint : MethodFingerprint( object PivotBarConstructorFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,

View File

@@ -3,12 +3,12 @@ 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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
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.fingerprints.PivotBarConstructorFingerprint
@@ -28,12 +28,12 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
PivotBarConstructorFingerprint PivotBarConstructorFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val result = PivotBarConstructorFingerprint.result!! val result = PivotBarConstructorFingerprint.result!!
val implementation = result.mutableMethod.implementation!! val implementation = result.mutableMethod.implementation!!
val pivotBarElementFieldRef = val pivotBarElementFieldRef =
(implementation.instructions[result.scanResult.patternScanResult!!.endIndex - 1] as Instruction22c).reference (implementation.instructions[result.patternScanResult!!.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
@@ -46,18 +46,16 @@ class RemoveUpgradeButtonPatch : BytecodePatch(
""".toInstructions().toMutableList() """.toInstructions().toMutableList()
val endIndex = result.scanResult.patternScanResult!!.endIndex
// replace the instruction to retain the label at given index // replace the instruction to retain the label at given index
implementation.replaceInstruction( implementation.replaceInstruction(
endIndex - 1, instructionList[0] // invoke-interface result.patternScanResult!!.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(
endIndex, exitInstruction result.patternScanResult!!.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()
@@ -66,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(endIndex) Opcode.IF_LE, 1, 2, implementation.newLabelForIndex(result.patternScanResult!!.endIndex)
) )
) )
implementation.addInstructions( implementation.addInstructions(
endIndex, instructionList result.patternScanResult!!.endIndex, instructionList
) )
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,8 +1,19 @@
package app.revanced.patches.music.misc.microg.fingerprints 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.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( object CastContextFetchFingerprint : MethodFingerprint(
strings = listOf("Error fetching CastContext.") strings = listOf("Error fetching CastContext.")
) )

View File

@@ -1,8 +1,19 @@
package app.revanced.patches.music.misc.microg.fingerprints 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.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( object CastDynamiteModuleFingerprint : MethodFingerprint(
strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl") strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl")
) )

View File

@@ -1,8 +1,19 @@
package app.revanced.patches.music.misc.microg.fingerprints 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.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( object CastDynamiteModuleV2Fingerprint : MethodFingerprint(
strings = listOf("Failed to load module via V2: ") strings = listOf("Failed to load module via V2: ")
) )

View File

@@ -1,9 +1,21 @@
package app.revanced.patches.music.misc.microg.fingerprints 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.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.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
@Name("google-play-utility-fingerprint")
@MatchingMethod(
"Lnuv;", "b"
)
@DirectPatternScanMethod
@MusicMicroGPatchCompatibility
@Version("0.0.1")
object GooglePlayUtilityFingerprint : MethodFingerprint( object GooglePlayUtilityFingerprint : MethodFingerprint(
"I", "I",
AccessFlags.PUBLIC or AccessFlags.STATIC, AccessFlags.PUBLIC or AccessFlags.STATIC,

View File

@@ -1,8 +1,19 @@
package app.revanced.patches.music.misc.microg.fingerprints 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.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( object PrimeFingerprint : MethodFingerprint(
strings = listOf("com.google.android.GoogleCamera", "com.android.vending") strings = listOf("com.google.android.GoogleCamera", "com.android.vending")
) )

View File

@@ -1,12 +1,21 @@
package app.revanced.patches.music.misc.microg.fingerprints 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.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod 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.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
import org.jf.dexlib2.AccessFlags 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. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@MusicMicroGPatchCompatibility
@Version("0.0.1")
object ServiceCheckFingerprint : MethodFingerprint( object ServiceCheckFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.STATIC, AccessFlags.PUBLIC or AccessFlags.STATIC,

View File

@@ -1,27 +1,37 @@
package app.revanced.patches.music.misc.microg.patch.bytecode 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.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.annotations.DependsOn 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.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.annotations.MusicMicroGPatchCompatibility
import app.revanced.patches.music.misc.microg.fingerprints.*
import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch
import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME 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.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.youtube.misc.microg.shared.Constants import app.revanced.patches.music.misc.microg.fingerprints.*
import app.revanced.util.microg.MicroGBytecodeHelper 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 @Patch
@DependsOn([MusicMicroGResourcePatch::class]) @DependsOn([MusicMicroGResourcePatch::class])
@Name("music-microg-support") @Name("music-microg-support")
@Description("Allows YouTube Music ReVanced to run without root and under a different package name.") @Description("Allows YouTube Music ReVanced to run without root and under a different package name.")
@MusicMicroGPatchCompatibility @MusicMicroGPatchCompatibility
@Version("0.0.2") @Version("0.0.1")
class MusicMicroGBytecodePatch : BytecodePatch( class MusicMicroGBytecodePatch : BytecodePatch(
listOf( listOf(
ServiceCheckFingerprint, ServiceCheckFingerprint,
@@ -32,34 +42,130 @@ class MusicMicroGBytecodePatch : BytecodePatch(
PrimeFingerprint, PrimeFingerprint,
) )
) { ) {
// NOTE: the previous patch also replaced the following strings, but it seems like they are not needed: override fun execute(data: BytecodeData): PatchResult {
// - "com.google.android.gms.chimera.GmsIntentOperationService", disablePlayServiceChecks()
// - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks", data.classes.forEach { classDef ->
// - "com.google.android.gms.phenotype.internal.IPhenotypeService", var proxiedClass: MutableClass? = null
// - "com.google.android.gms.phenotype.PACKAGE_NAME",
// - "com.google.android.gms.phenotype.UPDATE", classDef.methods.forEach methodLoop@{ method ->
// - "com.google.android.gms.phenotype", val implementation = method.implementation ?: return@methodLoop
override fun execute(context: BytecodeContext) =
// apply common microG patch var proxiedImplementation: MutableMethodImplementation? = null
MicroGBytecodeHelper.patchBytecode(
context, implementation.instructions.forEachIndexed { i, instruction ->
arrayOf( if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
MicroGBytecodeHelper.packageNameTransform(
Constants.PACKAGE_NAME, val stringValue = ((instruction as Instruction21c).reference as StringReference).string
Constants.REVANCED_PACKAGE_NAME
) val replaceMode = if (stringValue.equalsAny(
), "com.google.android.gms",
MicroGBytecodeHelper.PrimeMethodTransformationData( "com.google.android.gms.chimera",
PrimeFingerprint, "com.google.android.c2dm.intent.REGISTER",
MUSIC_PACKAGE_NAME, "com.google.android.c2dm.permission.SEND",
REVANCED_MUSIC_PACKAGE_NAME "com.google.iid.TOKEN_REQUEST",
), "com.google",
listOf( "com.google.android.gms.chimera.GmsIntentOperationService",
ServiceCheckFingerprint, "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks",
GooglePlayUtilityFingerprint, "com.google.android.gms.phenotype.internal.IPhenotypeService",
CastDynamiteModuleFingerprint, "com.google.android.gms.phenotype.service.START",
CastDynamiteModuleV2Fingerprint, "com.google.android.gms.phenotype.PACKAGE_NAME",
CastContextFetchFingerprint "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
) )
).let { PatchResultSuccess() } }
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\""
)
}
} }

View File

@@ -1,41 +1,44 @@
package app.revanced.patches.music.misc.microg.patch.resource package app.revanced.patches.music.misc.microg.patch.resource
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.ResourceContext import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME 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_APP_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_PACKAGE_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_PACKAGE_SIGNATURE @Name("music-microg-resource-patch")
import app.revanced.util.microg.MicroGManifestHelper @Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.")
import app.revanced.util.microg.MicroGResourceHelper @MusicMicroGPatchCompatibility
@Version("0.0.1")
@Name("music-microg-resource-patch") class MusicMicroGResourcePatch : ResourcePatch() {
@Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.") override fun execute(data: ResourceData): PatchResult {
@MusicMicroGPatchCompatibility
@Version("0.0.2") val manifest = data["AndroidManifest.xml"].readText()
class MusicMicroGResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult { data["AndroidManifest.xml"].writeText(
// update manifest manifest.replace(
MicroGResourceHelper.patchManifest( "package=\"com.google.android.apps.youtube.music", "package=\"$REVANCED_MUSIC_PACKAGE_NAME"
context, ).replace(
MUSIC_PACKAGE_NAME, "android:label=\"@string/app_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
REVANCED_MUSIC_PACKAGE_NAME, ).replace(
REVANCED_MUSIC_APP_NAME "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"
// add metadata to the manifest ).replace(
MicroGManifestHelper.addSpoofingMetadata( "com.google.android.apps.youtube.music.permission.C2D_MESSAGE", "$REVANCED_MUSIC_PACKAGE_NAME.permission.C2D_MESSAGE"
context, ).replace(
SPOOFED_PACKAGE_NAME, "com.google.android.c2dm", "$BASE_MICROG_PACKAGE_NAME.android.c2dm"
SPOOFED_PACKAGE_SIGNATURE ).replace(
) "</queries>", "<package android:name=\"$BASE_MICROG_PACKAGE_NAME.android.gms\"/></queries>"
return PatchResultSuccess() )
} )
return PatchResultSuccess()
}
} }

View File

@@ -1,9 +1,7 @@
package app.revanced.patches.music.misc.microg.shared package app.revanced.patches.music.misc.microg.shared
object Constants { object Constants {
internal const val REVANCED_MUSIC_APP_NAME = "YT Music ReVanced" 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" internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music" }
internal const val SPOOFED_PACKAGE_NAME = MUSIC_PACKAGE_NAME
internal const val SPOOFED_PACKAGE_SIGNATURE = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875"
}

View File

@@ -5,26 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility(
[Package( [Package(
"com.google.android.apps.youtube.music", "com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51", "5.17.51", "5.21.52", "5.22.54", "5.23.50")
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)] )]
) )
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)

View File

@@ -1,13 +1,22 @@
package app.revanced.patches.music.premium.backgroundplay.fingerprints package app.revanced.patches.music.premium.backgroundplay.fingerprints
import app.revanced.patcher.annotation.Name
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.fingerprint.method.impl.MethodFingerprint 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.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")
@MatchingMethod(
"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
@Version("0.0.1")
object BackgroundPlaybackDisableFingerprint : MethodFingerprint( object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( "Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
Opcode.CONST_4, Opcode.CONST_4,

View File

@@ -3,12 +3,12 @@ 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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
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.fingerprints.BackgroundPlaybackDisableFingerprint
@@ -22,7 +22,7 @@ class BackgroundPlayPatch : BytecodePatch(
BackgroundPlaybackDisableFingerprint BackgroundPlaybackDisableFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
BackgroundPlaybackDisableFingerprint.result!!.mutableMethod.addInstructions( BackgroundPlaybackDisableFingerprint.result!!.mutableMethod.addInstructions(
0, 0,
""" """

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.myexpenses.misc.pro.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("org.totschnig.myexpenses")])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class UnlockProCompatibility

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.myexpenses.misc.pro.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object IsEnabledFingerprint : MethodFingerprint(
"Z",
strings = listOf("feature", "feature.licenceStatus")
)

View File

@@ -1,38 +0,0 @@
package app.revanced.patches.myexpenses.misc.pro.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.myexpenses.misc.pro.annotations.UnlockProCompatibility
import app.revanced.patches.myexpenses.misc.pro.fingerprints.IsEnabledFingerprint
@Patch
@Name("unlock-pro")
@Description("Unlocks all professional features.")
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProPatch : BytecodePatch(
listOf(
IsEnabledFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val method = IsEnabledFingerprint.result!!.mutableMethod
method.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.nyx.misc.pro.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.awedea.nyx")])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class UnlockProCompatibility

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.nyx.misc.pro.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object CheckProFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("BillingManager;") && methodDef.name == "isProVersion"
}
)

View File

@@ -1,38 +0,0 @@
package app.revanced.patches.nyx.misc.pro.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.nyx.misc.pro.annotations.UnlockProCompatibility
import app.revanced.patches.nyx.misc.pro.fingerprints.CheckProFingerprint
@Patch
@Name("unlock-pro")
@Description("Unlocks all pro features.")
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProPatch : BytecodePatch(
listOf(
CheckProFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val method = CheckProFingerprint.result!!.mutableMethod
method.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -3,11 +3,7 @@ package app.revanced.patches.reddit.ad.general.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
@Compatibility( @Compatibility([Package("com.reddit.frontpage")])
[Package(
"com.reddit.frontpage", arrayOf("2022.43.0")
)]
)
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
internal annotation class GeneralAdsCompatibility internal annotation class GeneralAdsCompatibility

View File

@@ -3,11 +3,12 @@ package app.revanced.patches.reddit.ad.general.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.reddit.ad.general.annotations.GeneralAdsCompatibility import app.revanced.patches.reddit.ad.general.annotations.GeneralAdsCompatibility
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
@@ -21,8 +22,8 @@ import org.jf.dexlib2.immutable.reference.ImmutableStringReference
@GeneralAdsCompatibility @GeneralAdsCompatibility
@Version("0.0.1") @Version("0.0.1")
class GeneralAdsPatch : BytecodePatch() { class GeneralAdsPatch : BytecodePatch() {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
context.classes.forEach { classDef -> data.classes.forEach { classDef ->
classDef.methods.forEach methodLoop@{ method -> classDef.methods.forEach methodLoop@{ method ->
val implementation = method.implementation ?: return@methodLoop val implementation = method.implementation ?: return@methodLoop
@@ -30,7 +31,7 @@ class GeneralAdsPatch : BytecodePatch() {
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
if (((instruction as ReferenceInstruction).reference as StringReference).string != "AdPost") return@forEachIndexed if (((instruction as ReferenceInstruction).reference as StringReference).string != "AdPost") return@forEachIndexed
val proxiedClass = context.proxy(classDef).mutableClass val proxiedClass = data.proxy(classDef).resolve()
val proxiedImplementation = proxiedClass.methods.first { val proxiedImplementation = proxiedClass.methods.first {
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes) it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)

View File

@@ -1,7 +1,17 @@
package app.revanced.patches.reddit.layout.premiumicon.fingerprints 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.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( object PremiumIconFingerprint : MethodFingerprint(
"Z", "Z",
customFingerprint = { methodDef -> customFingerprint = { methodDef ->

View File

@@ -3,18 +3,18 @@ package app.revanced.patches.reddit.layout.premiumicon.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.BytecodeContext import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch 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.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.reddit.layout.premiumicon.annotations.PremiumIconCompatibility import app.revanced.patches.reddit.layout.premiumicon.annotations.PremiumIconCompatibility
import app.revanced.patches.reddit.layout.premiumicon.fingerprints.PremiumIconFingerprint import app.revanced.patches.reddit.layout.premiumicon.fingerprints.PremiumIconFingerprint
@Patch @Patch
@Name("premium-icon-reddit") @Name("premium-icon-reddit")
@Description("Unlocks premium Reddit app icons.") @Description("Unlocking Premium Icons in reddit app.")
@PremiumIconCompatibility @PremiumIconCompatibility
@Version("0.0.1") @Version("0.0.1")
class PremiumIconPatch : BytecodePatch( class PremiumIconPatch : BytecodePatch(
@@ -22,7 +22,7 @@ class PremiumIconPatch : BytecodePatch(
PremiumIconFingerprint PremiumIconFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(data: BytecodeData): PatchResult {
val method = PremiumIconFingerprint.result!!.mutableMethod val method = PremiumIconFingerprint.result!!.mutableMethod
method.addInstructions( method.addInstructions(
0, 0,

View File

@@ -1,9 +0,0 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object SeekbarFingerprint : MethodFingerprint(
"V",
strings = listOf("timed_markers_width")
)

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object SeekbarOnDrawFingerprint : MethodFingerprint(
customFingerprint = { it.name == "onDraw" }
)

View File

@@ -1,10 +0,0 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object WatchWhileActivityFingerprint : MethodFingerprint(
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("WatchWhileActivity;") && methodDef.name == "<init>"
}
)

View File

@@ -1,66 +0,0 @@
package app.revanced.patches.shared.integrations.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import org.jf.dexlib2.iface.Method
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
@Version("0.0.1")
abstract class AbstractIntegrationsPatch(
private val integrationsDescriptor: String,
private val hooks: Iterable<IntegrationsFingerprint>
) : BytecodePatch(hooks) {
/**
* [MethodFingerprint] for integrations.
*
* @param contextRegisterResolver A [RegisterResolver] to get the register.
* @see MethodFingerprint
*/
abstract class IntegrationsFingerprint(
strings: Iterable<String>? = null,
customFingerprint: ((methodDef: Method) -> Boolean)? = null,
private val contextRegisterResolver: (Method) -> Int = object : RegisterResolver {}
) : MethodFingerprint(strings = strings, customFingerprint = customFingerprint) {
fun invoke(integrationsDescriptor: String): PatchResult {
result?.mutableMethod?.let { method ->
val contextRegister = contextRegisterResolver(method)
method.addInstruction(
0,
"sput-object v$contextRegister, " +
"$integrationsDescriptor->context:Landroid/content/Context;"
)
} ?: return PatchResultError("Could not find hook target fingerprint.")
return PatchResultSuccess()
}
interface RegisterResolver : (Method) -> Int {
override operator fun invoke(method: Method) = method.implementation!!.registerCount - 1
}
}
override fun execute(context: BytecodeContext): PatchResult {
if (context.findClass(integrationsDescriptor) == null) return MISSING_INTEGRATIONS
for (hook in hooks) hook.invoke(integrationsDescriptor).let {
if (it is PatchResultError) return it
}
return PatchResultSuccess()
}
private companion object {
val MISSING_INTEGRATIONS = PatchResultError(
"Integrations have not been merged yet. " +
"This patch can not succeed without merging the integrations."
)
}
}

View File

@@ -1,73 +0,0 @@
package app.revanced.patches.shared.mapping.misc.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import org.w3c.dom.Element
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
@Name("resource-mapping")
@Description("Creates a map of public resources.")
@Version("0.0.1")
class ResourceMappingPatch : ResourcePatch {
companion object {
internal lateinit var resourceMappings: List<ResourceElement>
private set
private val THREAD_COUNT = Runtime.getRuntime().availableProcessors()
private val threadPoolExecutor = Executors.newFixedThreadPool(THREAD_COUNT)
}
override fun execute(context: ResourceContext): PatchResult {
// save the file in memory to concurrently read from
val resourceXmlFile = context["res/values/public.xml"].readBytes()
// create a synchronized list to store the resource mappings
val mappings = Collections.synchronizedList(mutableListOf<ResourceElement>())
for (threadIndex in 0 until THREAD_COUNT) {
threadPoolExecutor.execute thread@{
context.xmlEditor[resourceXmlFile.inputStream()].use { editor ->
val resources = editor.file.documentElement.childNodes
val resourcesLength = resources.length
val jobSize = resourcesLength / THREAD_COUNT
val batchStart = jobSize * threadIndex
val batchEnd = jobSize * (threadIndex + 1)
element@ for (i in batchStart until batchEnd) {
// make sure to not to go out of bounds when rounding errors occur at calculating the jobSize
if (i >= resourcesLength) return@thread
val node = resources.item(i)
if (node !is Element) continue
val nameAttribute = node.getAttribute("name")
val typeAttribute = node.getAttribute("type")
if (node.nodeName != "public" || nameAttribute.startsWith("APKTOOL")) continue
val id = node.getAttribute("id").substring(2).toLong(16)
mappings.add(ResourceElement(typeAttribute, nameAttribute, id))
}
}
}
}
threadPoolExecutor
.also { it.shutdown() }
.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
resourceMappings = mappings
return PatchResultSuccess()
}
}
data class ResourceElement(val type: String, val name: String, val id: Long)

View File

@@ -1,31 +0,0 @@
package app.revanced.patches.shared.settings.preference
import app.revanced.patches.shared.settings.preference.impl.StringResource
import org.w3c.dom.Document
import org.w3c.dom.Element
/**
* Base preference class for all preferences.
*
* @param key The key of the preference.
* @param title The title of the preference.
*/
internal abstract class BasePreference(
override val key: String,
override val title: StringResource,
) : IPreference {
/**
* Serialize preference element to XML.
* Overriding methods should invoke super and operate on its return value.
* @param ownerDocument Target document to create elements from.
* @param resourceCallback Called when a resource has been processed.
*/
open fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)? = null): Element {
return ownerDocument.createElement(tag).apply {
if(key.isNotEmpty())
setAttribute("android:key", key)
setAttribute("android:title", "@string/${title.also { resourceCallback?.invoke(it) }.name}")
}
}
}

View File

@@ -1,26 +0,0 @@
package app.revanced.patches.shared.settings.preference
import org.w3c.dom.Document
import org.w3c.dom.Element
/**
* Base resource class for all resources.
*
* @param name The name of the resource.
*/
internal abstract class BaseResource(
override val name: String
) : IResource {
/**
* Serialize resource element to XML.
* Overriding methods should invoke super and operate on its return value.
* @param ownerDocument Target document to create elements from.
* @param resourceCallback Called when a resource has been processed.
*/
open fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)? = null): Element {
return ownerDocument.createElement(tag).apply {
setAttribute("name", name)
}
}
}

View File

@@ -1,42 +0,0 @@
package app.revanced.patches.shared.settings.preference
import app.revanced.patches.shared.settings.preference.impl.StringResource
import org.w3c.dom.Element
import org.w3c.dom.Node
/**
* Add a resource node child
*
* @param resource The resource to add.
* @param resourceCallback Called when a resource has been processed.
*/
internal fun Node.addResource(resource: BaseResource, resourceCallback: ((IResource) -> Unit)? = null) {
appendChild(resource.serialize(ownerDocument, resourceCallback))
}
/**
* Add a preference node child to the settings.
*
* @param preference The preference to add.
* @param resourceCallback Called when a resource has been processed.
*/
internal fun Node.addPreference(preference: BasePreference, resourceCallback: ((IResource) -> Unit)? = null) {
appendChild(preference.serialize(ownerDocument, resourceCallback))
}
internal fun Element.addSummary(summaryResource: StringResource?, summaryType: SummaryType = SummaryType.DEFAULT) =
summaryResource?.let { summary ->
setAttribute("android:${summaryType.type}", "@string/${summary.name}")
}
internal fun <T> Element.addDefault(default: T) {
default?.let {
setAttribute(
"android:defaultValue", when (it) {
is Boolean -> if (it) "true" else "false"
is String -> it
else -> throw IllegalArgumentException("Unsupported default value type: ${it::class.java.name}")
}
)
}
}

View File

@@ -1,16 +0,0 @@
package app.revanced.patches.shared.settings.preference
/**
* Resource
*/
internal interface IResource {
/**
* Name of the resource.
*/
val name: String
/**
* Tag name of the resource.
*/
val tag: String
}

View File

@@ -1,5 +0,0 @@
package app.revanced.patches.shared.settings.preference
enum class SummaryType(val type: String) {
DEFAULT("summary"), ON("summaryOn"), OFF("summaryOff")
}

View File

@@ -1,33 +0,0 @@
package app.revanced.patches.shared.settings.preference.impl
import app.revanced.patches.shared.settings.preference.BaseResource
import app.revanced.patches.shared.settings.preference.IResource
import org.w3c.dom.Document
import org.w3c.dom.Element
/**
* Represents an array resource.
*
* @param name The name of the array resource.
* @param items The items of the array resource.
*/
internal data class ArrayResource(
override val name: String,
val items: List<StringResource>
) : BaseResource(name) {
override val tag = "string-array"
override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element {
return super.serialize(ownerDocument, resourceCallback).apply {
setAttribute("name", name)
items.forEach { item ->
resourceCallback?.invoke(item)
this.appendChild(ownerDocument.createElement("item").also { itemNode ->
itemNode.textContent = "@string/${item.name}"
})
}
}
}
}

View File

@@ -1,38 +0,0 @@
package app.revanced.patches.shared.settings.preference.impl
import app.revanced.patches.shared.settings.preference.BasePreference
import app.revanced.patches.shared.settings.preference.IResource
import app.revanced.patches.shared.settings.preference.addDefault
import app.revanced.patches.shared.settings.preference.addSummary
import org.w3c.dom.Document
import org.w3c.dom.Element
/**
* List preference.
*
* @param key The key of the list preference.
* @param title The title of the list preference.
* @param entries The human-readable entries of the list preference.
* @param entryValues The entry values of the list preference.
* @param default The default entry value of the list preference.
* @param summary The summary of the list preference.
*/
internal class ListPreference(
key: String,
title: StringResource,
val entries: ArrayResource,
val entryValues: ArrayResource,
val default: String? = null,
val summary: StringResource? = null
) : BasePreference(key, title) {
override val tag: String = "ListPreference"
override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element {
return super.serialize(ownerDocument, resourceCallback).apply {
setAttribute("android:entries", "@array/${entries.also { resourceCallback?.invoke(it) }.name}")
setAttribute("android:entryValues", "@array/${entryValues.also { resourceCallback?.invoke(it) }.name}")
addDefault(default)
addSummary(summary)
}
}
}

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