bump v2.147.0

This commit is contained in:
inotia00
2022-12-23 17:49:31 +09:00
parent 74aecf4720
commit 187d905bdb
1034 changed files with 21004 additions and 11645 deletions

View File

@ -1,3 +1,17 @@
# [2.147.0](https://github.com/revanced/revanced-patches/compare/v2.146.0...v2.147.0) (2022-12-21)
### Features
* **youtube/return-youtube-dislike:** debug connection statistics, toast on error, high priority background threads ([#1320](https://github.com/revanced/revanced-patches/issues/1320)) ([30273a9](https://github.com/revanced/revanced-patches/commit/30273a9bbdd40453baeb09f26ac9d218569a3e71))
# [2.147.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.146.0...v2.147.0-dev.1) (2022-12-21)
### Features
* **youtube/return-youtube-dislike:** debug connection statistics, toast on error, high priority background threads ([#1320](https://github.com/revanced/revanced-patches/issues/1320)) ([30273a9](https://github.com/revanced/revanced-patches/commit/30273a9bbdd40453baeb09f26ac9d218569a3e71))
# [2.146.0](https://github.com/revanced/revanced-patches/compare/v2.145.0...v2.146.0) (2022-12-18) # [2.146.0](https://github.com/revanced/revanced-patches/compare/v2.145.0...v2.146.0) (2022-12-18)

347
README.md
View File

@ -9,53 +9,67 @@ The official Patch bundle provided by ReVanced and the community.
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `always-autorepeat` | Always repeats the playing video again. | 17.49.37 | | `client-spoof` | Spoofs the YouTube client to prevent playback issues. | 17.49.37 |
| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all | | `custom-branding-icon-blue` | Changes the YouTube launcher icon (ReVanced Blue). | 17.49.37 |
| `comments` | Hides components related to comments. | 17.49.37 | | `custom-branding-icon-red` | Changes the YouTube launcher icon (ReVanced Red). | 17.49.37 |
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all | | `custom-branding-icon-revancify` | Changes the YouTube launcher icon (Revancify). | 17.49.37 |
| `custom-branding-name` | Changes the YouTube launcher name to your choice (defaults to ReVanced Extended). | 17.49.37 |
| `custom-video-buffer` | Lets you change the buffers of videos. | 17.49.37 | | `custom-video-buffer` | Lets you change the buffers of videos. | 17.49.37 |
| `custom-video-speed` | Adds more video speed options. | 17.49.37 | | `custom-video-speed` | Adds more video speed options. | 17.49.37 |
| `debugging` | Adds debugging options. | all | | `default-video-quality` | Adds ability to set default video quality settings. | 17.49.37 |
| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 17.49.37 | | `default-video-speed` | Adds ability to set default video speed settings. | 17.49.37 |
| `disable-auto-player-popup-panels` | Disable automatic popup panels (playlist or live chat) on video player. | 17.49.37 | | `disable-haptic-feedback` | Disable haptic feedback when swiping. | 17.49.37 |
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 17.49.37 | | `enable-external-browser` | Use an external browser to open the url. | 17.49.37 |
| `disable-startup-shorts-player` | Disables playing YouTube Shorts when launching YouTube. | 17.49.37 | | `enable-hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.49.37 |
| `disable-zoom-haptics` | Disables haptics when zooming. | all | | `enable-minimized-playback` | Enables minimized and background playback. | 17.49.37 |
| `downloads` | Enables downloading music and videos from YouTube. | 17.49.37 | | `enable-old-layout` | Spoof the YouTube client version to use the old layout. | 17.49.37 |
| `enable-oldstyle-quality-layout` | Enables the original quality flyout menu. | 17.49.37 |
| `enable-open-links-directly` | Bypass URL redirects (youtube.com/redirect) when opening links in video descriptions. | 17.49.37 |
| `enable-seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.49.37 |
| `enable-tablet-miniplayer` | Enables the tablet mini player layout. | 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 | | `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 | | `force-premium-heading` | Forces premium heading on the home screen. | 17.49.37 |
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.49.37 | | `header-switch` | Add switch to change header. | 17.49.37 |
| `hide-album-cards` | Hides the album cards below the artist description. | 17.49.37 | | `hide-auto-captions` | Hide captions from being automatically enabled. | 17.49.37 |
| `hide-artist-card` | Hides the artist card below the searchbar. | 17.49.37 | | `hide-auto-player-popup-panels` | Hide automatic popup panels (playlist or live chat) on video player. | 17.49.37 |
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.49.37 | | `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.49.37 |
| `hide-captions-button` | Hides the captions button on video player. | 17.49.37 | | `hide-button-container` | Adds options to hide action buttons under a video. | 17.49.37 |
| `hide-cast-button` | Hides the cast button in the video player. | all | | `hide-cast-button` | Hides the cast button in the video player. | 17.49.37 |
| `hide-channel-watermark` | Hides creator's watermarks on videos. | 17.49.37 |
| `hide-comment-component` | Adds options to hide comment component under a video. | 17.49.37 |
| `hide-create-button` | Hides the create button in the navigation bar. | 17.49.37 | | `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-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-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-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 17.49.37 |
| `hide-endscreen-overlay` | Hide endscreen overlay on swipe controls. | 17.49.37 |
| `hide-filmstrip-overlay` | Hide flimstrip overlay on swipe controls. | 17.49.37 |
| `hide-flyout-panel` | Adds options to hide player settings flyout panel. | 17.49.37 |
| `hide-fullscreen-buttoncontainer` | Hides the button containers in fullscreen. | 17.49.37 |
| `hide-general-ads` | Hooks the method which parses the bytes into a ComponentContext to filter components. | 17.49.37 |
| `hide-info-cards` | Hides info-cards in videos. | 17.49.37 | | `hide-info-cards` | Hides info-cards in videos. | 17.49.37 |
| `hide-my-mix` | Hides mix playlists. | 17.49.37 | | `hide-mix-playlists` | Removes mix playlists from home feed and video player. | 17.49.37 |
| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 17.49.37 | | `hide-pip-notification` | Disable pip notification when you first launch pip mode. | 17.49.37 |
| `hide-player-captions-button` | Hides the captions button in the video player. | 17.49.37 |
| `hide-player-overlay-filter` | Hide the suggested actions bar inside the player. | 17.49.37 |
| `hide-shorts-button` | Hides the shorts button in the navigation bar. | 17.49.37 |
| `hide-shorts-component` | Hides other Shorts components. | 17.49.37 |
| `hide-startup-shorts-player` | Disables playing YouTube Shorts when launching YouTube. | 17.49.37 |
| `hide-stories` | Hides YouTube Stories shelf on the feed. | 17.49.37 |
| `hide-suggested-actions` | Hide the suggested actions bar inside the player. | 17.49.37 |
| `hide-time-and-seekbar` | Hides progress bar and time counter on videos. | 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-video-ads` | Removes ads in the video player. | 17.49.37 |
| `hide-watch-in-vr` | Hides the Watch in VR option in the player settings flyout panel. | 17.49.37 | | `layout-switch` | Tricks the dpi to use some tablet/phone layouts. | 17.49.37 |
| `hide-watermark` | Hides creator's watermarks on videos. | 17.49.37 | | `materialyou` | Enables MaterialYou theme for Android 12+ | 17.49.37 |
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 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 | | `optimize-resource` | Removes duplicate resources and adds missing translation files from YouTube. | 17.49.37 |
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 17.49.37 | | `overlay-buttons` | Add overlay buttons for ReVanced Extended. | 17.49.37 |
| `open-links-directly` | Bypasses URL redirects and opens links directly inside YouTube app. | 17.49.37 |
| `premium-heading` | Shows premium branding on the home screen. | all |
| `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 | | `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 | | `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` | Applies mandatory patches to implement ReVanced settings into the application. | 17.49.37 |
| `settings` | Adds settings for ReVanced to YouTube. | all |
| `sponsorblock` | Integrate SponsorBlock. | 17.49.37 | | `sponsorblock` | Integrate SponsorBlock. | 17.49.37 |
| `swipe-controls` | Adds volume and brightness swipe controls. | 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 (default: amoled). | 17.49.37 |
| `theme` | Applies a custom theme. | all | | `translations` | Add Crowdin Translations | 17.49.37 |
| `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.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music)
@ -63,186 +77,27 @@ The official Patch bundle provided by ReVanced and the community.
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `background-play` | Enables playing music in the background. | 5.36.51 | | `background-play` | Enables playing music in the background. | all |
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.36.51 | | `black-navbar` | Sets the navigation bar color to black. | all |
| `compact-header` | Hides the music category bar at the top of the homepage. | 5.36.51 | | `client-spoof-music` | Spoofs the YouTube Music client. | all |
| `exclusive-audio-playback` | Enables the option to play music without video. | 5.36.51 | | `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | all |
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.36.51 | | `compact-header` | Hides the music category bar at the top of the homepage. | all |
| `minimized-playback-music` | Enables minimized playback on Kids music. | 5.36.51 | | `custom-branding-music-red` | Changes the YouTube Music launcher icon to your choice (defaults to ReVanced Red). | all |
| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | 5.36.51 | | `custom-branding-music-revancify` | Changes the YouTube Music launcher icon to your choice (Revancify). | all |
| `music-video-ads` | Removes ads in the music player. | 5.36.51 | | `exclusive-audio-playback` | Enables the option to play music without video. | all |
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.36.51 | | `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | all |
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.36.51 | | `hide-music-cast-button` | Hides the cast button in the video player and header | all |
</details> | `minimized-playback-music` | Enables minimized playback on Kids music. | all |
| `minimized-player` | Permanently keep player minimized even if another track is played. | all |
### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill) | `miniplayer-color` | Matches the fullscreen player color with the minimized one. | all |
<details> | `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | all |
| `music-settings` | Adds settings for ReVanced to YouTube Music. | all |
| 💊 Patch | 📜 Description | 🏹 Target Version | | `music-video-ads` | Removes ads in the music player. | all |
|:--------:|:--------------:|:-----------------:| | `optimize-resource-music` | Remove unnecessary resources. | all |
| `disable-login-requirement` | Do not force login. | all | | `tablet-mode` | Unlocks landscape mode. | all |
| `downloads` | Removes download restrictions and changes the default path to download to. | all | | `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | all |
| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | all | | `translations-music` | Add Crowdin Translations for YouTube Music | all |
| `fix-google-login` | Allows logging in with a Google account. | all | | `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 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. | all |
| `show-seekbar` | Shows progress bar for all video. | all |
| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | all |
</details>
### [📦 `com.zhiliaoapp.musically`](https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-login-requirement` | Do not force login. | all |
| `downloads` | Removes download restrictions and changes the default path to download to. | all |
| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | all |
| `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. | all |
| `show-seekbar` | Shows progress bar for all video. | all |
| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | all |
</details>
### [📦 `tv.twitch.android.app`](https://play.google.com/store/apps/details?id=tv.twitch.android.app)
<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.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.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 |
| `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.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. | all |
| `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>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all |
</details>
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all professional features. | all |
</details>
### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | 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>
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all 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> </details>
@ -288,76 +143,10 @@ Example:
{ {
"name": "com.google.android.youtube", "name": "com.google.android.youtube",
"versions": [ "versions": [
"17.22.36", "17.49.37"
"17.24.35",
"17.26.35",
"17.27.39",
"17.28.34",
"17.29.34",
"17.32.35",
"17.33.42"
] ]
} }
] ]
},
{
"name": "theme",
"description": "Enables a custom theme.",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "theme",
"title": "Theme",
"description": "Select a theme.",
"required": true,
"choices": [
"Amoled"
]
}
],
"dependencies": [
"locale-config-fix"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": []
}
]
},
{
"name": "custom-branding",
"description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "appName",
"title": "Application Name",
"description": "The name of the application it will show on your home screen.",
"required": true,
"choices": null
},
{
"key": "appIconPath",
"title": "Application Icon Path",
"description": "A path to the icon of the application.",
"required": false,
"choices": null
}
],
"dependencies": [
"locale-config-fix"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": []
}
]
} }
] ]
``` ```

View File

@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 2.146.0 version = 2.147.0

File diff suppressed because one or more lines are too long

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

@ -1,30 +0,0 @@
package app.revanced.patches.music.ad.video.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class MusicVideoAdsCompatibility

View File

@ -1,27 +0,0 @@
package app.revanced.patches.music.ad.video.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID
)
)

View File

@ -1,14 +0,0 @@
package app.revanced.patches.music.ad.video.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 ShowMusicVideoAdsFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf(
Opcode.IPUT_BOOLEAN,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
)
)

View File

@ -5,35 +5,38 @@ 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.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.util.smali.ExternalLabel
import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.patches.videoads.GeneralVideoAdsPatch
@Patch @Patch
@DependsOn(
[
GeneralVideoAdsPatch::class,
MusicIntegrationsPatch::class,
MusicSettingsPatch::class
]
)
@Name("music-video-ads") @Name("music-video-ads")
@Description("Removes ads in the music player.") @Description("Removes ads in the music player.")
@MusicVideoAdsCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class MusicVideoAdsPatch : BytecodePatch( class MusicVideoAdsPatch : BytecodePatch() {
listOf(
ShowMusicVideoAdsConstructorFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef) val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/settings/MusicSettings;->getShowAds()Z"
val result = ShowMusicVideoAdsFingerprint.result!! GeneralVideoAdsPatch.injectLegacyAds(INTEGRATIONS_CLASS_DESCRIPTOR)
result.mutableMethod.addInstructions( GeneralVideoAdsPatch.injectMainstreamAds(INTEGRATIONS_CLASS_DESCRIPTOR)
result.scanResult.patternScanResult!!.startIndex, """
const/4 p1, 0x0
"""
)
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.audio.codecs.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class CodecsUnlockCompatibility

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object AllCodecsReferenceFingerprint : MethodFingerprint( object AllCodecsReferenceFingerprint : MethodFingerprint(
"J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( "J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(

View File

@ -1,13 +1,18 @@
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.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@Name("codec-lock-fingerprint")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@YouTubeMusicCompatibility
@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,

View File

@ -5,20 +5,26 @@ 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.BytecodeContext
import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.util.smali.ExternalLabel
import app.revanced.patcher.util.smali.toInstruction
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
import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprint import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@Patch @Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("codecs-unlock") @Name("codecs-unlock")
@Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.") @Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.")
@CodecsUnlockCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class CodecsUnlockPatch : BytecodePatch( class CodecsUnlockPatch : BytecodePatch(
listOf( listOf(
@ -27,8 +33,9 @@ class CodecsUnlockPatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val codecsLockResult = CodecsLockFingerprint.result!! val codecsLockResult = CodecsLockFingerprint.result!!
val codecsLockMethod = codecsLockResult.mutableMethod
val implementation = codecsLockResult.mutableMethod.implementation!! val implementation = codecsLockMethod.implementation!!
val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex
val instructionIndex = scanResultStartIndex + val instructionIndex = scanResultStartIndex +
@ -46,9 +53,14 @@ class CodecsUnlockPatch : BytecodePatch(
.nextMethod(allCodecsResult.scanResult.patternScanResult!!.startIndex) .nextMethod(allCodecsResult.scanResult.patternScanResult!!.startIndex)
.getMethod() .getMethod()
implementation.replaceInstruction( codecsLockMethod.addInstructions(
instructionIndex, instructionIndex + 2, """
"invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction() invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getCodecsUnlock()Z
move-result v7
if-eqz v7, :mp4a
invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;
move-result-object p4
""", listOf(ExternalLabel("mp4a", codecsLockMethod.instruction(instructionIndex + 2)))
) )
return PatchResultSuccess() return PatchResultSuccess()

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.audio.exclusiveaudio.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class ExclusiveAudioCompatibility

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object ExclusiveAudioFingerprint : MethodFingerprint( object ExclusiveAudioFingerprint : MethodFingerprint(
"V", "V",

View File

@ -6,17 +6,17 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
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.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.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.shared.annotation.YouTubeMusicCompatibility
@Patch @Patch
@Name("exclusive-audio-playback") @Name("exclusive-audio-playback")
@Description("Enables the option to play music without video.") @Description("Enables the option to play music without video.")
@ExclusiveAudioCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class ExclusiveAudioPatch : BytecodePatch( class ExclusiveAudioPatch : BytecodePatch(
listOf( listOf(

View File

@ -0,0 +1,84 @@
package app.revanced.patches.music.layout.blacknavbar.bytecode.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.instruction
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.extensions.findMutableMethodOf
import app.revanced.shared.patches.mapping.ResourceMappingPatch
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.Opcode
@Patch
@DependsOn(
[
MusicIntegrationsPatch::class,
MusicSettingsPatch::class,
ResourceMappingPatch::class
]
)
@Name("black-navbar")
@Description("Sets the navigation bar color to black.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class BlackNavbarPatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"ytm_color_grey_12"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // blacknavbar
val insertIndex = index - 1
val insertIndex2 = index + 2
val invokeInstruction = instructions.elementAt(insertIndex)
val invokeInstruction2 = instructions.elementAt(insertIndex2)
if (invokeInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return@forEachIndexed
val register1 = (instructions.elementAt(index) as Instruction31i).registerA
val register2 = (invokeInstruction2 as Instruction11x).registerA
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
mutableMethod.addInstructions(
index + 3, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getBlackNavbar()Z
move-result v$register1
if-eqz v$register1, :default
const/high16 v$register2, -0x1000000
""", listOf(ExternalLabel("default", mutableMethod.instruction(index + 3)))
)
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,111 @@
package app.revanced.patches.music.layout.branding.icon.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.*
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import java.nio.file.Files
import java.nio.file.StandardCopyOption
@Patch
@Name("custom-branding-music-red")
@Description("Changes the YouTube Music launcher icon to your choice (defaults to ReVanced Red).")
@YouTubeMusicCompatibility
@Version("0.0.1")
class CustomBrandingMusicPatch_Red : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
val classLoader = this.javaClass.classLoader
val resDirectory = context["res"]
if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.")
// App Icon
val AppiconNames = arrayOf(
"adaptiveproduct_youtube_music_background_color_108",
"adaptiveproduct_youtube_music_foreground_color_108",
"ic_launcher_release"
)
mapOf(
"xxxhdpi" to 192,
"xxhdpi" to 144,
"xhdpi" to 96,
"hdpi" to 72,
"mdpi" to 48
).forEach { (iconDirectory, size) ->
AppiconNames.forEach iconLoop@{ iconName ->
Files.copy(
classLoader.getResourceAsStream("music/branding/red/launchericon/$size/$iconName.png")!!,
resDirectory.resolve("mipmap-$iconDirectory").resolve("$iconName.png").toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
// Other Resource
val drawables1 = "drawable-hdpi" to arrayOf(
"action_bar_logo",
"action_bar_logo_release",
"record"
)
val drawables2 = "drawable-large-hdpi" to arrayOf(
"record"
)
val drawables3 = "drawable-large-mdpi" to arrayOf(
"record"
)
val drawables4 = "drawable-large-xhdpi" to arrayOf(
"record"
)
val drawables5 = "drawable-mdpi" to arrayOf(
"action_bar_logo",
"record"
)
val drawables6 = "drawable-xhdpi" to arrayOf(
"action_bar_logo",
"record"
)
val drawables7 = "drawable-xlarge-hdpi" to arrayOf(
"record"
)
val drawables8 = "drawable-xlarge-mdpi" to arrayOf(
"record"
)
val drawables9 = "drawable-xxhdpi" to arrayOf(
"action_bar_logo",
"record"
)
val drawables10 = "drawable-xxxhdpi" to arrayOf(
"action_bar_logo"
)
val pngResources = arrayOf(drawables1, drawables2, drawables3, drawables4, drawables5, drawables6, drawables7, drawables8, drawables9, drawables10)
pngResources.forEach { (path, resourceNames) ->
resourceNames.forEach { name ->
val relativePath = "$path/$name.png"
Files.copy(
classLoader.getResourceAsStream("music/branding/red/resource/$relativePath")!!,
context["res"].resolve(relativePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,64 @@
package app.revanced.patches.music.layout.branding.icon.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.*
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import java.nio.file.Files
import java.nio.file.StandardCopyOption
@Patch(false)
@Name("custom-branding-music-revancify")
@Description("Changes the YouTube Music launcher icon to your choice (Revancify).")
@YouTubeMusicCompatibility
@Version("0.0.1")
class CustomBrandingMusicPatch_Revancify : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
val classLoader = this.javaClass.classLoader
val resDirectory = context["res"]
if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.")
// App Icon
val AppiconNames = arrayOf(
"adaptiveproduct_youtube_music_background_color_108",
"adaptiveproduct_youtube_music_foreground_color_108",
"ic_launcher_release"
)
mapOf(
"xxxhdpi" to 192,
"xxhdpi" to 144,
"xhdpi" to 96,
"hdpi" to 72,
"mdpi" to 48
).forEach { (iconDirectory, size) ->
AppiconNames.forEach iconLoop@{ iconName ->
Files.copy(
classLoader.getResourceAsStream("music/branding/revancify/launchericon/$size/$iconName.png")!!,
resDirectory.resolve("mipmap-$iconDirectory").resolve("$iconName.png").toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
// MonoChrome Icon
arrayOf("drawable" to arrayOf("ic_app_icons_themed_youtube_music")).forEach { (path, resourceNames) ->
resourceNames.forEach { name ->
val relativePath = "$path/$name.xml"
Files.copy(
classLoader.getResourceAsStream("music/branding/revancify/monochromeicon/$relativePath")!!,
context["res"].resolve(relativePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,15 @@
package app.revanced.patches.music.layout.castbutton.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
@Name("hide-castbutton-signature")
@YouTubeMusicCompatibility
@Version("0.0.1")
object HideCastButtonFingerprint : MethodFingerprint (
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("I"), null ,null, null
)

View File

@ -0,0 +1,16 @@
package app.revanced.patches.music.layout.castbutton.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
@Name("hide-castbutton-parent-signature")
@YouTubeMusicCompatibility
@Version("0.0.1")
object HideCastButtonParentFingerprint : MethodFingerprint (
"Z", AccessFlags.PRIVATE or AccessFlags.FINAL,
strings = listOf("MediaRouteButton")
)

View File

@ -0,0 +1,46 @@
package app.revanced.patches.music.layout.castbutton.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.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
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.patches.music.layout.castbutton.fingerprints.HideCastButtonFingerprint
import app.revanced.patches.music.layout.castbutton.fingerprints.HideCastButtonParentFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("hide-music-cast-button")
@Description("Hides the cast button in the video player and header")
@YouTubeMusicCompatibility
@Version("0.0.1")
class HideWatermarkPatch : BytecodePatch(
listOf(
HideCastButtonParentFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
HideCastButtonFingerprint.resolve(context, HideCastButtonParentFingerprint.result!!.classDef)
val result = HideCastButtonFingerprint.result
?: return PatchResultError("Required parent method could not be found.")
result.mutableMethod.addInstructions(
0, """
invoke-static {p1}, Lapp/revanced/integrations/settings/MusicSettings;->getCastButtonOverrideV2(I)I
move-result p1
"""
)
return PatchResultSuccess()
}
}

View File

@ -1,29 +0,0 @@
package app.revanced.patches.music.layout.compactheader.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class CompactHeaderCompatibility

View File

@ -1,10 +1,16 @@
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.shared.annotation.YouTubeMusicCompatibility
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")
@YouTubeMusicCompatibility
@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

@ -5,18 +5,22 @@ 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.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.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 app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
@Patch(false) @Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("compact-header") @Name("compact-header")
@Description("Hides the music category bar at the top of the homepage.") @Description("Hides the music category bar at the top of the homepage.")
@CompactHeaderCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class CompactHeaderPatch : BytecodePatch( class CompactHeaderPatch : BytecodePatch(
listOf( listOf(
@ -31,7 +35,8 @@ class CompactHeaderPatch : BytecodePatch(
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, """
const/16 v2, 0x8 invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getCompactHeader()I
move-result v2
invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V
""" """
) )

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.layout.minimizedplayback.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class MinimizedPlaybackCompatibility

View File

@ -1,10 +1,16 @@
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.shared.annotation.YouTubeMusicCompatibility
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")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MinimizedPlaybackManagerFingerprint : MethodFingerprint( object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, AccessFlags.PUBLIC or AccessFlags.FINAL,

View File

@ -4,18 +4,22 @@ 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.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.util.proxy.mutableTypes.MutableMethod
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 app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@Patch @Patch
@Name("minimized-playback-music") @Name("minimized-playback-music")
@Description("Enables minimized playback on Kids music.") @Description("Enables minimized playback on Kids music.")
@MinimizedPlaybackCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class MinimizedPlaybackPatch : BytecodePatch( class MinimizedPlaybackPatch : BytecodePatch(
listOf( listOf(
@ -23,10 +27,8 @@ class MinimizedPlaybackPatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions( MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstruction(
0, """ 0, "return-void"
return-void
"""
) )
return PatchResultSuccess() return PatchResultSuccess()

View File

@ -0,0 +1,28 @@
package app.revanced.patches.music.layout.minimizedplayer.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("minimized-player-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MinimizedPlayerFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L"), listOf(
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.CONST_4,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL
),
strings = listOf("w_st")
)

View File

@ -0,0 +1,51 @@
package app.revanced.patches.music.layout.minimizedplayer.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.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
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.util.smali.ExternalLabel
import app.revanced.patches.music.layout.minimizedplayer.fingerprints.MinimizedPlayerFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("minimized-player")
@Description("Permanently keep player minimized even if another track is played.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class MinimizedPlayerPatch : BytecodePatch(
listOf(
MinimizedPlayerFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = MinimizedPlayerFingerprint.result!!
val method = result.mutableMethod
val index = result.scanResult.patternScanResult!!.endIndex
val register = (method.implementation!!.instructions[index - 1] as OneRegisterInstruction).registerA - 1
val jumpInstruction = method.implementation!!.instructions[index + 1] as Instruction
method.addInstructions(
index, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getEnforceMinimizedPlayer()Z
move-result v$register
if-nez v$register, :enforce
""", listOf(ExternalLabel("enforce", jumpInstruction))
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,20 @@
package app.revanced.patches.music.layout.miniplayercolor.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("miniplayer-color-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MiniplayerColorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "J"), listOf(
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID
)
)

View File

@ -0,0 +1,33 @@
package app.revanced.patches.music.layout.miniplayercolor.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("miniplayer-color-hook-fingerprint")
@YouTubeMusicCompatibility
@Version("0.0.1")
object MiniplayerColorParentFingerprint : MethodFingerprint(
"V",
AccessFlags.PRIVATE or AccessFlags.FINAL,
null,
listOf(
Opcode.IGET,
Opcode.IGET,
Opcode.CONST_WIDE_16,
Opcode.IF_EQ,
Opcode.IPUT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET,
Opcode.IGET,
Opcode.IF_EQ,
Opcode.IPUT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL
)
)

View File

@ -0,0 +1,99 @@
package app.revanced.patches.music.layout.miniplayercolor.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.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorFingerprint
import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorParentFingerprint
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("miniplayer-color")
@Description("Matches the fullscreen player color with the minimized one.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class MiniplayerColorPatch : BytecodePatch(
listOf(
MiniplayerColorFingerprint, MiniplayerColorParentFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val miniplayerColorParentResult = MiniplayerColorParentFingerprint.result!!
val miniplayerColorParentMethod = miniplayerColorParentResult.mutableMethod
MiniplayerColorFingerprint.resolve(context, miniplayerColorParentResult.classDef)
val miniplayerColorResult = MiniplayerColorFingerprint.result!!
val miniplayerColorMethod = miniplayerColorResult.mutableMethod
val insertIndex = miniplayerColorResult.scanResult.patternScanResult!!.startIndex + 1
val jumpInstruction = miniplayerColorMethod.implementation!!.instructions[insertIndex] as Instruction
val Reference_A_1 =
miniplayerColorParentMethod.let { method ->
(method.implementation!!.instructions.elementAt(4) as ReferenceInstruction).reference as FieldReference
}
val Reference_A_2 =
miniplayerColorParentMethod.let { method ->
(method.implementation!!.instructions.elementAt(5) as ReferenceInstruction).reference as FieldReference
}
val Reference_A_3 =
miniplayerColorParentMethod.let { method ->
(method.implementation!!.instructions.elementAt(6) as ReferenceInstruction).reference as MethodReference
}
val Reference_B_1 =
miniplayerColorParentMethod.let { method ->
(method.implementation!!.instructions.elementAt(10) as ReferenceInstruction).reference as FieldReference
}
val Reference_B_2 =
miniplayerColorParentMethod.let { method ->
(method.implementation!!.instructions.elementAt(11) as ReferenceInstruction).reference as FieldReference
}
val Reference_B_3 =
miniplayerColorParentMethod.let { method ->
(method.implementation!!.instructions.elementAt(12) as ReferenceInstruction).reference as MethodReference
}
miniplayerColorMethod.addInstructions(
insertIndex, """
invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getMiniPlayerColor()Z
move-result v2
if-eqz v2, :off
iget v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_1.name}:${Reference_A_1.type}
if-eq v0, v2, :abswitch
iput v2, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_1.name}:${Reference_A_1.type}
iget-object v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_2.name}:${Reference_A_2.type}
invoke-virtual {v0, v2, p2, p3}, $Reference_A_3
:abswitch
iget v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_B_1.name}:${Reference_B_1.type}
if-eq v0, v1, :exit
iput v1, p0, ${miniplayerColorResult.classDef.type}->${Reference_B_1.name}:${Reference_B_1.type}
iget-object v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_B_2.name}:${Reference_B_2.type}
invoke-virtual {v0, v1, p2, p3}, $Reference_B_3
goto :exit
:off
invoke-direct {p0}, ${miniplayerColorResult.classDef.type}->${miniplayerColorParentResult.mutableMethod.name}()V
""", listOf(ExternalLabel("exit", jumpInstruction))
)
miniplayerColorMethod.removeInstruction(insertIndex - 1)
return PatchResultSuccess()
}
}

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.layout.premium.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class HideGetPremiumCompatibility

View File

@ -1,10 +1,16 @@
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.shared.annotation.YouTubeMusicCompatibility
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")
@YouTubeMusicCompatibility
@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,16 @@
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.shared.annotation.YouTubeMusicCompatibility
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")
@YouTubeMusicCompatibility
@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

@ -7,18 +7,18 @@ import app.revanced.patcher.data.BytecodeContext
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.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.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
import app.revanced.shared.annotation.YouTubeMusicCompatibility
@Patch @Patch
@Name("hide-get-premium") @Name("hide-get-premium")
@Description("Removes all \"Get Premium\" evidences from the avatar menu.") @Description("Removes all \"Get Premium\" evidences from the avatar menu.")
@HideGetPremiumCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideGetPremiumPatch : BytecodePatch( class HideGetPremiumPatch : BytecodePatch(
listOf( listOf(

View File

@ -0,0 +1,75 @@
package app.revanced.patches.music.layout.tabletmode.bytecode.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.instruction
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.extensions.findMutableMethodOf
import app.revanced.shared.patches.mapping.ResourceMappingPatch
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.Opcode
@Patch
@DependsOn(
[
MusicIntegrationsPatch::class,
MusicSettingsPatch::class,
ResourceMappingPatch::class
]
)
@Name("tablet-mode")
@Description("Unlocks landscape mode.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class TabletModePatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"is_tablet"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // tablet
val insertIndex = index - 2
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
mutableMethod.addInstructions(
index + 3, """
invoke-static {p0}, Lapp/revanced/integrations/settings/MusicSettings;->getTabletMode(Z)Z
move-result p0
"""
)
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
return PatchResultSuccess()
}
}

View File

@ -1,32 +0,0 @@
package app.revanced.patches.music.layout.tastebuilder.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
/**
* -- Note 2022-08-05 --
* Since 5.17.xx the tastebuilder component is dismissible, so this patch is less useful
* also it is partly litho now
*/
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class RemoveTasteBuilderCompatibility

View File

@ -1,13 +1,18 @@
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.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
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")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@YouTubeMusicCompatibility
@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

@ -5,18 +5,18 @@ 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.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.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 app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.iface.instruction.formats.Instruction22c import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@Patch @Patch
@Name("tasteBuilder-remover") @Name("tasteBuilder-remover")
@Description("Removes the \"Tell us which artists you like\" card from the home screen.") @Description("Removes the \"Tell us which artists you like\" card from the home screen.")
@RemoveTasteBuilderCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class RemoveTasteBuilderPatch : BytecodePatch( class RemoveTasteBuilderPatch : BytecodePatch(
listOf( listOf(

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.layout.upgradebutton.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class RemoveUpgradeButtonCompatibility

View File

@ -1,13 +1,18 @@
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.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
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")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@YouTubeMusicCompatibility
@Version("0.0.1")
object PivotBarConstructorFingerprint : MethodFingerprint( object PivotBarConstructorFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,

View File

@ -5,23 +5,23 @@ 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.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.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.fingerprints.PivotBarConstructorFingerprint import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint
import org.jf.dexlib2.Opcode import app.revanced.shared.annotation.YouTubeMusicCompatibility
import org.jf.dexlib2.builder.instruction.BuilderInstruction22t import org.jf.dexlib2.builder.instruction.BuilderInstruction22t
import org.jf.dexlib2.iface.instruction.formats.Instruction22c import org.jf.dexlib2.iface.instruction.formats.Instruction22c
import org.jf.dexlib2.iface.instruction.formats.Instruction35c import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.Opcode
@Patch @Patch
@Name("upgrade-button-remover") @Name("upgrade-button-remover")
@Description("Removes the upgrade tab from the pivot bar.") @Description("Removes the upgrade tab from the pivot bar.")
@RemoveUpgradeButtonCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class RemoveUpgradeButtonPatch : BytecodePatch( class RemoveUpgradeButtonPatch : BytecodePatch(
listOf( listOf(

View File

@ -0,0 +1,10 @@
package app.revanced.patches.music.misc.clientspoof.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
parameters = listOf("L"),
opcodes = listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL, Opcode.CONST_16),
strings = listOf("(Linux; U; Android ")
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.misc.fix.spoof.patch package app.revanced.patches.music.misc.clientspoof.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
@ -6,30 +6,31 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.patches.music.misc.clientspoof.fingerprints.UserAgentHeaderBuilderFingerprint
import app.revanced.patches.youtube.misc.fix.spoof.annotations.ClientSpoofCompatibility import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.youtube.misc.fix.spoof.fingerprints.UserAgentHeaderBuilderFingerprint
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch @Patch
@Name("client-spoof") @Name("client-spoof-music")
@Description("Spoofs the YouTube or Vanced client to prevent playback issues.") @Description("Spoofs the YouTube Music client.")
@ClientSpoofCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class ClientSpoofPatch : BytecodePatch( class ClientSpoofMusicPatch : BytecodePatch(
listOf(UserAgentHeaderBuilderFingerprint) listOf(UserAgentHeaderBuilderFingerprint)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = UserAgentHeaderBuilderFingerprint.result!! val result = UserAgentHeaderBuilderFingerprint.result!!
val method = result.mutableMethod val method = result.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex val insertIndex = result.scanResult.patternScanResult!!.endIndex - 1
val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD
val originalPackageName = "com.google.android.youtube" val originalPackageName = "com.google.android.apps.youtube.music"
method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"") method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"")
return PatchResultSuccess() return PatchResultSuccess()

View File

@ -0,0 +1,7 @@
package app.revanced.patches.music.misc.integrations.fingerprints
import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint
object InitFingerprint : IntegrationsFingerprint(
strings = listOf("YouTubeMusic", "activity")
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.music.misc.integrations.patch
import app.revanced.patcher.annotation.Name
import app.revanced.patches.music.misc.integrations.fingerprints.InitFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch
@Name("music-integrations")
@YouTubeMusicCompatibility
class MusicIntegrationsPatch : AbstractIntegrationsPatch(
"Lapp/revanced/integrations/settings/MusicSettings;",
listOf(InitFingerprint),
)

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.misc.microg.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class MusicMicroGPatchCompatibility

View File

@ -1,5 +1,4 @@
package app.revanced.patches.music.misc.microg.fingerprints package app.revanced.patches.music.misc.microg.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View File

@ -1,5 +1,4 @@
package app.revanced.patches.music.misc.microg.fingerprints package app.revanced.patches.music.misc.microg.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View File

@ -1,5 +1,4 @@
package app.revanced.patches.youtube.misc.microg.fingerprints package app.revanced.patches.music.misc.microg.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View File

@ -1,18 +1,18 @@
package app.revanced.patches.music.misc.microg.fingerprints package app.revanced.patches.music.misc.microg.bytecode.fingerprints
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 org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
object GooglePlayUtilityFingerprint : MethodFingerprint( object GooglePlayUtilityFingerprint : MethodFingerprint(
"I", "I",
AccessFlags.PUBLIC or AccessFlags.STATIC, AccessFlags.PUBLIC or AccessFlags.STATIC,
listOf("L", "I"), listOf("L", "I"),
strings = listOf( strings = listOf(
"This should never happen.", "This should never happen.",
"MetadataValueReader", "MetadataValueReader",
"GooglePlayServicesUtil", "GooglePlayServicesUtil",
"com.android.vending", "com.android.vending",
"android.hardware.type.embedded" "android.hardware.type.embedded"
) )
) )

View File

@ -1,5 +1,4 @@
package app.revanced.patches.youtube.misc.microg.fingerprints package app.revanced.patches.music.misc.microg.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View File

@ -1,15 +1,14 @@
package app.revanced.patches.music.misc.microg.fingerprints package app.revanced.patches.music.misc.microg.bytecode.fingerprints
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.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object ServiceCheckFingerprint : MethodFingerprint(
object ServiceCheckFingerprint : MethodFingerprint( "V",
"V", AccessFlags.PUBLIC or AccessFlags.STATIC,
AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"),
listOf("L", "I"), strings = listOf("Google Play Services not available")
strings = listOf("Google Play Services not available") )
)

View File

@ -1,65 +1,79 @@
package app.revanced.patches.music.misc.microg.patch.bytecode package app.revanced.patches.music.misc.microg.bytecode.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.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.PatchResult
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.music.misc.microg.fingerprints.* import app.revanced.patches.music.misc.clientspoof.patch.ClientSpoofMusicPatch
import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch import app.revanced.patches.music.misc.microg.bytecode.fingerprints.*
import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.resource.patch.MusicMicroGResourcePatch
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.YOUTUBE_PACKAGE_NAME
import app.revanced.patches.youtube.misc.microg.shared.Constants import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME
import app.revanced.util.microg.MicroGBytecodeHelper import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.patches.options.PatchOptions
@Patch import app.revanced.shared.util.microg.MicroGBytecodeHelper
@DependsOn([MusicMicroGResourcePatch::class])
@Name("music-microg-support") @Patch
@Description("Allows YouTube Music ReVanced to run without root and under a different package name.") @DependsOn(
@MusicMicroGPatchCompatibility [
@Version("0.0.2") ClientSpoofMusicPatch::class,
class MusicMicroGBytecodePatch : BytecodePatch( MusicMicroGResourcePatch::class,
listOf( PatchOptions::class
ServiceCheckFingerprint, ]
GooglePlayUtilityFingerprint, )
CastDynamiteModuleFingerprint, @Name("music-microg-support")
CastDynamiteModuleV2Fingerprint, @Description("Allows YouTube Music ReVanced to run without root and under a different package name.")
CastContextFetchFingerprint, @YouTubeMusicCompatibility
PrimeFingerprint, @Version("0.0.2")
) class MusicMicroGBytecodePatch : BytecodePatch(
) { listOf(
// NOTE: the previous patch also replaced the following strings, but it seems like they are not needed: ServiceCheckFingerprint,
// - "com.google.android.gms.chimera.GmsIntentOperationService", GooglePlayUtilityFingerprint,
// - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks", CastDynamiteModuleFingerprint,
// - "com.google.android.gms.phenotype.internal.IPhenotypeService", CastDynamiteModuleV2Fingerprint,
// - "com.google.android.gms.phenotype.PACKAGE_NAME", CastContextFetchFingerprint,
// - "com.google.android.gms.phenotype.UPDATE", PrimeFingerprint,
// - "com.google.android.gms.phenotype", )
override fun execute(context: BytecodeContext) = ) {
// apply common microG patch // NOTE: the previous patch also replaced the following strings, but it seems like they are not needed:
MicroGBytecodeHelper.patchBytecode( // - "com.google.android.gms.chimera.GmsIntentOperationService",
context, // - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks",
arrayOf( // - "com.google.android.gms.phenotype.internal.IPhenotypeService",
MicroGBytecodeHelper.packageNameTransform( // - "com.google.android.gms.phenotype.PACKAGE_NAME",
Constants.PACKAGE_NAME, // - "com.google.android.gms.phenotype.UPDATE",
Constants.REVANCED_PACKAGE_NAME // - "com.google.android.gms.phenotype",
) override fun execute(context: BytecodeContext): PatchResult {
), var YouTubePackageName = PatchOptions.YouTube_PackageName
MicroGBytecodeHelper.PrimeMethodTransformationData( var MusicPackageName = PatchOptions.Music_PackageName
PrimeFingerprint,
MUSIC_PACKAGE_NAME, // apply common microG patch
REVANCED_MUSIC_PACKAGE_NAME MicroGBytecodeHelper.patchBytecode(
), context,
listOf( arrayOf(
ServiceCheckFingerprint, MicroGBytecodeHelper.packageNameTransform(
GooglePlayUtilityFingerprint, YOUTUBE_PACKAGE_NAME,
CastDynamiteModuleFingerprint, "$YouTubePackageName"
CastDynamiteModuleV2Fingerprint, )
CastContextFetchFingerprint ),
) MicroGBytecodeHelper.PrimeMethodTransformationData(
).let { PatchResultSuccess() } PrimeFingerprint,
} MUSIC_PACKAGE_NAME,
"$MusicPackageName"
),
listOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint
)
)
return PatchResultSuccess()
}
}

View File

@ -1,33 +1,39 @@
package app.revanced.patches.music.misc.microg.patch.resource package app.revanced.patches.music.misc.microg.resource.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.ResourceContext import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.annotations.DependsOn
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.ResourcePatch
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.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_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 import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_PACKAGE_SIGNATURE
import app.revanced.util.microg.MicroGManifestHelper import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.microg.MicroGResourceHelper import app.revanced.shared.patches.options.PatchOptions
import app.revanced.shared.util.microg.MicroGManifestHelper
import app.revanced.shared.util.microg.MicroGResourceHelper
@Name("music-microg-resource-patch") @Name("music-microg-resource-patch")
@Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.") @Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.")
@MusicMicroGPatchCompatibility @DependsOn(
[
PatchOptions::class
]
)
@YouTubeMusicCompatibility
@Version("0.0.2") @Version("0.0.2")
class MusicMicroGResourcePatch : ResourcePatch { class MusicMicroGResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult { override fun execute(context: ResourceContext): PatchResult {
var MusicPackageName = PatchOptions.Music_PackageName
// update manifest // update manifest
MicroGResourceHelper.patchManifest( MicroGResourceHelper.patchManifest(
context, context,
MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME,
REVANCED_MUSIC_PACKAGE_NAME, "$MusicPackageName"
REVANCED_MUSIC_APP_NAME
) )
// add metadata to the manifest // add metadata to the manifest

View File

@ -1,9 +1,8 @@
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 YOUTUBE_PACKAGE_NAME = "com.google.android.youtube"
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music" internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music"
internal const val SPOOFED_PACKAGE_NAME = MUSIC_PACKAGE_NAME internal const val SPOOFED_PACKAGE_NAME = MUSIC_PACKAGE_NAME
internal const val SPOOFED_PACKAGE_SIGNATURE = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875" internal const val SPOOFED_PACKAGE_SIGNATURE = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875"
} }

View File

@ -0,0 +1,33 @@
package app.revanced.patches.music.misc.optimizeresource.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.annotations.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import java.nio.file.Files
import java.nio.file.StandardCopyOption
@Patch
@Name("optimize-resource-music")
@Description("Remove unnecessary resources.")
@YouTubeMusicCompatibility
@Version("0.0.1")
class OptimizeResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
val relativePath = "raw/third_party_licenses"
Files.copy(
this.javaClass.classLoader.getResourceAsStream("youtube/resource/$relativePath")!!,
context["res"].resolve(relativePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,60 @@
package app.revanced.patches.music.misc.settings.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.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode
import org.w3c.dom.Element
@Patch
@Name("music-settings")
@Description("Adds settings for ReVanced to YouTube Music.")
@YouTubeMusicCompatibility
@DependsOn([FixLocaleConfigErrorPatch::class])
@Version("0.0.1")
class MusicSettingsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
/*
* Copy strings
*/
context.copyXmlNode("music/settings/host", "values/strings.xml", "resources")
/*
* Copy colors
*/
context.xmlEditor["res/values/colors.xml"].use { editor ->
val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element
for (i in 0 until resourcesNode.childNodes.length) {
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
node.textContent = when (node.getAttribute("name")) {
"material_deep_teal_500" -> "@android:color/white"
else -> continue
}
}
}
/*
* Copy preference fragments
*/
context.copyXmlNode("music/settings/host", "xml/settings_headers.xml", "PreferenceScreen")
context.copyXmlNode("music/settings/host", "xml/settings_prefs_compat.xml", "com.google.android.apps.youtube.music.ui.preference.PreferenceCategoryCompat")
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,86 @@
package app.revanced.patches.youtube.misc.translations.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.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch
import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
import app.revanced.shared.annotation.YouTubeMusicCompatibility
import java.nio.file.Files
import java.nio.file.StandardCopyOption
@Patch
@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class])
@Name("translations-music")
@Description("Add Crowdin Translations for YouTube Music")
@YouTubeMusicCompatibility
@Version("0.0.1")
class MusicTranslationsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
val revanced_translations = "translate" to arrayOf(
"ar-v21",
"az-rAZ-v21",
"bg-rBG-v21",
"bn-rIN-v21",
"bn-v21",
"cs-rCZ-v21",
"de-rDE-v21",
"el-rGR-v21",
"es-rES-v21",
"fi-rFI-v21",
"fr-rFR-v21",
"hi-rIN-v21",
"hu-rHU-v21",
"id-rID-v21",
"in-v21",
"it-rIT-v21",
"ja-rJP-v21",
"kn-rIN-v21",
"ko-rKR-v21",
"ml-rIN-v21",
"nl-rNL-v21",
"pa-rIN-v21",
"pl-rPL-v21",
"pt-rBR-v21",
"pt-rPT-v21",
"ro-rRO-v21",
"ru-rRU-v21",
"sk-rSK-v21",
"sv-rFI-v21",
"sv-rSE-v21",
"ta-rIN-v21",
"th-v21",
"tr-rTR-v21",
"uk-rUA-v21",
"vi-rVN-v21",
"zh-rCN-v21",
"zh-rTW-v21"
)
val TranslationsResources = arrayOf(revanced_translations)
val classLoader = this.javaClass.classLoader
TranslationsResources.forEach { (path, languageNames) ->
languageNames.forEach { name ->
val resDirectory = context["res"].resolve("values-$name")
val relativePath = "values-$name/strings.xml"
Files.createDirectory(resDirectory.toPath())
Files.copy(
classLoader.getResourceAsStream("music/$path/$relativePath")!!,
context["res"].resolve(relativePath).toPath(),
StandardCopyOption.REPLACE_EXISTING
)
}
}
return PatchResultSuccess()
}
}

View File

@ -1,30 +0,0 @@
package app.revanced.patches.music.premium.backgroundplay.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"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"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class BackgroundPlayCompatibility

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object BackgroundPlaybackDisableFingerprint : MethodFingerprint( object BackgroundPlaybackDisableFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( "Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(

View File

@ -5,17 +5,17 @@ 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.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.BytecodePatch 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.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint
import app.revanced.shared.annotation.YouTubeMusicCompatibility
@Patch @Patch
@Name("background-play") @Name("background-play")
@Description("Enables playing music in the background.") @Description("Enables playing music in the background.")
@BackgroundPlayCompatibility @YouTubeMusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class BackgroundPlayPatch : BytecodePatch( class BackgroundPlayPatch : BytecodePatch(
listOf( listOf(

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

@ -1,9 +0,0 @@
package app.revanced.patches.reddit.ad.general.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.reddit.frontpage")])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class GeneralAdsCompatibility

View File

@ -1,54 +0,0 @@
package app.revanced.patches.reddit.ad.general.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
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.reddit.ad.general.annotations.GeneralAdsCompatibility
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.StringReference
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
@Patch
@Name("general-reddit-ads")
@Description("Removes general ads from the Reddit frontpage and subreddits.")
@GeneralAdsCompatibility
@Version("0.0.1")
class GeneralAdsPatch : BytecodePatch() {
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach methodLoop@{ method ->
val implementation = method.implementation ?: return@methodLoop
implementation.instructions.forEachIndexed { i, instruction ->
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
if (((instruction as ReferenceInstruction).reference as StringReference).string != "AdPost") return@forEachIndexed
val proxiedClass = context.proxy(classDef).mutableClass
val proxiedImplementation = proxiedClass.methods.first {
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
}.implementation!!
var newString = "AdPost1"
if (proxiedImplementation.instructions[i - 1].opcode == Opcode.CONST_STRING) {
newString = "SubredditPost"
}
proxiedImplementation.replaceInstruction(
i, BuilderInstruction21c(
Opcode.CONST_STRING, (proxiedImplementation.instructions[i] as BuilderInstruction21c).registerA, ImmutableStringReference(newString)
)
)
}
}
}
return PatchResultSuccess()
}
}

View File

@ -1,9 +0,0 @@
package app.revanced.patches.reddit.layout.premiumicon.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.reddit.frontpage")])
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class PremiumIconCompatibility

View File

@ -1,10 +0,0 @@
package app.revanced.patches.reddit.layout.premiumicon.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PremiumIconFingerprint : MethodFingerprint(
"Z",
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("MyAccount;") && methodDef.name == "isPremiumSubscriber"
}
)

View File

@ -1,36 +0,0 @@
package app.revanced.patches.reddit.layout.premiumicon.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.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.reddit.layout.premiumicon.annotations.PremiumIconCompatibility
import app.revanced.patches.reddit.layout.premiumicon.fingerprints.PremiumIconFingerprint
@Patch
@Name("premium-icon-reddit")
@Description("Unlocks premium Reddit app icons.")
@PremiumIconCompatibility
@Version("0.0.1")
class PremiumIconPatch : BytecodePatch(
listOf(
PremiumIconFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val method = PremiumIconFingerprint.result!!.mutableMethod
method.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

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,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,23 +0,0 @@
package app.revanced.patches.shared.settings.preference
import app.revanced.patches.shared.settings.preference.impl.StringResource
/**
* Preference
*/
internal interface IPreference {
/**
* Key of the preference.
*/
val key: String
/**
* Title of the preference.
*/
val title: StringResource
/**
* Tag name of the preference.
*/
val tag: String
}

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,6 +0,0 @@
package app.revanced.patches.shared.settings.preference.impl
enum class InputType(val type: String) {
STRING("text"),
NUMBER("number"),
}

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