diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..097f9f98
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,9 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat text eol=crlf
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e201fcbb..1ff5dc7d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,38 @@
+# [2.182.0-dev.5](https://github.com/revanced/revanced-patches/compare/v2.182.0-dev.4...v2.182.0-dev.5) (2023-07-08)
+
+
+### Bug Fixes
+
+* **youtube/hide-layout-components:** hide mix playlists ([33a87bd](https://github.com/revanced/revanced-patches/commit/33a87bd6eac1639687ebdf96ef8924cd674f81e4))
+
+# [2.182.0-dev.4](https://github.com/revanced/revanced-patches/compare/v2.182.0-dev.3...v2.182.0-dev.4) (2023-07-07)
+
+
+### Features
+
+* **youtube:** support version `18.23.35` ([#2461](https://github.com/revanced/revanced-patches/issues/2461)) ([d20fde1](https://github.com/revanced/revanced-patches/commit/d20fde1e57077fe9a943f9782b415d7a0249b083))
+
+# [2.182.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.182.0-dev.2...v2.182.0-dev.3) (2023-07-05)
+
+
+### Features
+
+* **pixiv:** add `hide-ads` patch ([#2578](https://github.com/revanced/revanced-patches/issues/2578)) ([862a7ec](https://github.com/revanced/revanced-patches/commit/862a7ec5b0767c28e79454a44218069d3e9cbac7))
+
+# [2.182.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.182.0-dev.1...v2.182.0-dev.2) (2023-07-05)
+
+
+### Features
+
+* **slideforreddit:** add `change-oauth-client-id` patch ([#2571](https://github.com/revanced/revanced-patches/issues/2571)) ([8cd60ee](https://github.com/revanced/revanced-patches/commit/8cd60eea36bd49514ed1c42bf362dce7e9675fca))
+
+# [2.182.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.181.0...v2.182.0-dev.1) (2023-07-05)
+
+
+### Features
+
+* remove unnecessary notice ([7e9f0b2](https://github.com/revanced/revanced-patches/commit/7e9f0b2d02e910984f08777fefcd2ad7df6a21ee))
+
# [2.181.0](https://github.com/revanced/revanced-patches/compare/v2.180.0...v2.181.0) (2023-07-03)
diff --git a/README-template.md b/README-template.md
deleted file mode 100644
index 5f21d12d..00000000
--- a/README-template.md
+++ /dev/null
@@ -1,122 +0,0 @@
-## 🧩 ReVanced Patches
-
-The official ReVanced Patches.
-
-## 📋 List of patches in this repository
-
-{{ table }}
-
-> Looking for the JSON variant of this? [Click here](patches.json).
-
-## 📝 JSON Format
-
-This section explains the JSON format for the [patches.json](patches.json) file.
-
-The file contains an array of objects, each object representing a patch. The object contains the following properties:
-
-| key | description |
-|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `name` | The name of the patch. |
-| `description` | The description of the patch. |
-| `version` | The version of the patch. |
-| `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. |
-| `options` | An array of options for this patch. |
-| `options.key` | The key of the option. |
-| `options.title` | The title of the option. |
-| `options.description` | The description of the option. |
-| `options.required` | Whether the option is required. |
-| `options.choices?` | An array of choices of the option. This may be `null` if this option has no choices. The element type of this array may be any type. It can be a `String`, `Int` or something else. |
-| `dependencies` | An array of dependencies, which are patch names. |
-| `compatiblePackages` | An array of packages compatible with this patch. |
-| `compatiblePackages.name` | The name of the package. |
-| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. |
-
-Example:
-
-```json
-[
- {
- "name": "remember-video-quality",
- "description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
- "version": "0.0.1",
- "excluded": false,
- "options": [],
- "dependencies": [
- "integrations",
- "video-id-hook"
- ],
- "compatiblePackages": [
- {
- "name": "com.google.android.youtube",
- "versions": [
- "17.22.36",
- "17.24.35",
- "17.26.35",
- "17.27.39",
- "17.28.34",
- "17.29.34",
- "17.32.35",
- "17.33.42"
- ]
- }
- ]
- },
- {
- "name": "theme",
- "description": "Enables a custom theme.",
- "version": "0.0.1",
- "excluded": 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,
- "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": []
- }
- ]
- }
-]
-```
\ No newline at end of file
diff --git a/README.md b/README.md
index f28416a9..79fde2b8 100644
--- a/README.md
+++ b/README.md
@@ -1,619 +1,3 @@
## 🧩 ReVanced Patches
-The official ReVanced Patches.
-
-## 📋 List of patches in this repository
-
-### [📦 `com.google.android.youtube`](https://play.google.com/store/apps/details?id=com.google.android.youtube)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `always-autorepeat` | Always repeats the playing video again. | 18.19.35 |
-| `client-spoof` | Spoofs a patched client to allow playback. | 18.19.35 |
-| `comments` | Hides components related to comments. | 18.19.35 |
-| `copy-video-url` | Adds buttons in player to copy video links. | 18.19.35 |
-| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
-| `custom-video-buffer` | Lets you change the buffers of videos. | 18.19.35 |
-| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.19.35 |
-| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.19.35 |
-| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.19.35 |
-| `disable-shorts-on-startup` | Disables playing YouTube Shorts when launching YouTube. | 18.19.35 |
-| `disable-zoom-haptics` | Disables haptics when zooming. | all |
-| `enable-debugging` | Adds debugging options. | all |
-| `external-downloads` | Adds support to download and save YouTube videos using an external app. | 18.19.35 |
-| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.19.35 |
-| `hide-ads` | Removes general ads. | 18.19.35 |
-| `hide-album-cards` | Hides the album cards below the artist description. | 18.19.35 |
-| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.19.35 |
-| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.19.35 |
-| `hide-captions-button` | Hides the captions button on video player. | 18.19.35 |
-| `hide-cast-button` | Hides the cast button in the video player. | all |
-| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.19.35 |
-| `hide-email-address` | Hides the email address in the account switcher. | 18.19.35 |
-| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.19.35 |
-| `hide-filter-bar` | Hides the filter bar in video feeds. | 18.19.35 |
-| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.19.35 |
-| `hide-info-cards` | Hides info cards in videos. | 18.19.35 |
-| `hide-layout-components` | Hides general layout components. | 18.19.35 |
-| `hide-load-more-button` | Hides the button under videos that loads similar videos. | 18.19.35 |
-| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | 18.19.35 |
-| `hide-player-overlay` | Hides the dark background overlay from the player when player controls are visible. | all |
-| `hide-seekbar` | Hides the seekbar. | 18.19.35 |
-| `hide-shorts-components` | Hides components from YouTube Shorts. | 18.19.35 |
-| `hide-timestamp` | Hides timestamp in video player. | 18.19.35 |
-| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.19.35 |
-| `hide-watch-in-vr` | Hides the option to watch in VR from the player settings flyout panel. | 18.19.35 |
-| `hide-watermark` | Hides creator's watermarks on videos. | 18.19.35 |
-| `minimized-playback` | Enables minimized and background playback. | 18.19.35 |
-| `navigation-buttons` | Adds options to hide or change navigation buttons. | 18.19.35 |
-| `old-quality-layout` | Enables the original video quality flyout in the video player settings. | 18.19.35 |
-| `open-links-externally` | Open links outside of the app directly in your browser. | 18.19.35 |
-| `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. | 18.19.35 |
-| `remove-player-controls-background` | Removes the background from the video player controls. | 18.19.35 |
-| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.19.35 |
-| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.19.35 |
-| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.19.35 |
-| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.19.35 |
-| `swipe-controls` | Adds volume and brightness swipe controls. | 18.19.35 |
-| `tablet-mini-player` | Enables the tablet mini player layout. | 18.19.35 |
-| `theme` | Applies a custom theme. | all |
-| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.19.35 |
-| `video-ads` | Removes ads in the video player. | 18.19.35 |
-| `video-speed` | Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout. | 18.19.35 |
-| `wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.19.35 |
-
-
-### [📦 `com.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `background-play` | Enables playing music in the background. | all |
-| `bypass-certificate-checks` | Bypasses certificate checks which prevent YouTube Music from working on Android Auto. | all |
-| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | all |
-| `compact-header` | Hides the music category bar at the top of the homepage. | all |
-| `exclusive-audio-playback` | Enables the option to play music without video. | all |
-| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | all |
-| `minimized-playback-music` | Enables minimized playback on Kids music. | all |
-| `music-video-ads` | Removes ads in the music player. | all |
-| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | all |
-| `vanced-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | all |
-
-
-### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill)
-
-
-| 💊 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 |
-
-
-### [📦 `com.zhiliaoapp.musically`](https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically)
-
-
-| 💊 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 |
-
-
-### [📦 `tv.twitch.android.app`](https://play.google.com/store/apps/details?id=tv.twitch.android.app)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `auto-claim-channel-points` | Automatically claim Channel Points. | 15.4.1 |
-| `block-audio-ads` | Blocks audio ads in streams and VODs. | 15.4.1 |
-| `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 15.4.1 |
-| `block-video-ads` | Blocks video ads in streams and VODs. | 15.4.1 |
-| `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. | 15.4.1 |
-
-
-### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `disable-screenshot-popup` | Disables the popup that shows up when taking a screenshot. | all |
-| `hide-ads` | Removes ads from the Reddit. | all |
-| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
-| `sanitize-sharing-links` | Removes (tracking) query parameters from the URLs when sharing links. | all |
-
-
-### [📦 `com.twitter.android`](https://play.google.com/store/apps/details?id=com.twitter.android)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `dynamic-color` | Replaces the default Twitter Blue with the users Material You palette. | all |
-| `hide-ads` | Hides ads. | all |
-| `hide-recommended-users` | Hides recommended users. | all |
-| `hide-views-stats` | Hides the view stats under tweets. | 9.71.0-release.0 |
-
-
-### [📦 `com.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `disable-switching-emoji-to-sticker-in-message-input-field` | Disables switching from emoji to sticker search mode in message input field | all |
-| `disable-typing-indicator` | Disables the indicator while typing a message | all |
-| `hide-inbox-ads` | Hides ads in inbox. | all |
-
-
-### [📦 `com.laurencedawson.reddit_sync`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "http://redditsync/auth". | all |
-| `disable-ads` | Disables ads. | all |
-
-
-### [📦 `com.spotify.music`](https://play.google.com/store/apps/details?id=com.spotify.music)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `hide-premium-navbar` | Removes the premium tab from the navbar. | all |
-| `spotify-theme` | Applies a custom theme. | all |
-
-
-### [📦 `com.sony.songpal.mdr`](https://play.google.com/store/apps/details?id=com.sony.songpal.mdr)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-badge-tab` | Removes the badge tab from the activity tab. | all |
-| `remove-notification-badge` | Removes the red notification badge from the activity tab. | all |
-
-
-### [📦 `at.gv.bmf.bmf2go`](https://play.google.com/store/apps/details?id=at.gv.bmf.bmf2go)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-bootloader-detection` | Removes the check for an unlocked bootloader. | all |
-| `remove-root-detection` | Removes the check for root permissions. | all |
-
-
-### [📦 `at.gv.oe.app`](https://play.google.com/store/apps/details?id=at.gv.oe.app)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-root-detection` | Removes the check for root permissions and unlocked bootloader. | all |
-| `spoof-signature` | Spoofs the signature of the app. | all |
-
-
-### [📦 `ml.docilealligator.infinityforreddit`](https://play.google.com/store/apps/details?id=ml.docilealligator.infinityforreddit)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "infinity://localhost". | all |
-
-
-### [📦 `free.reddit.news`](https://play.google.com/store/apps/details?id=free.reddit.news)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "dbrady://relay". | all |
-
-
-### [📦 `reddit.news`](https://play.google.com/store/apps/details?id=reddit.news)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "dbrady://relay". | all |
-
-
-### [📦 `com.onelouder.baconreader`](https://play.google.com/store/apps/details?id=com.onelouder.baconreader)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "http://baconreader.com/auth". | all |
-
-
-### [📦 `com.onelouder.baconreader.premium`](https://play.google.com/store/apps/details?id=com.onelouder.baconreader.premium)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "http://baconreader.com/auth". | all |
-
-
-### [📦 `com.rubenmayayo.reddit`](https://play.google.com/store/apps/details?id=com.rubenmayayo.reddit)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "http://rubenmayayo.com". | all |
-
-
-### [📦 `com.andrewshu.android.reddit`](https://play.google.com/store/apps/details?id=com.andrewshu.android.reddit)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "redditisfun://auth". | all |
-
-
-### [📦 `com.andrewshu.android.redditdonation`](https://play.google.com/store/apps/details?id=com.andrewshu.android.redditdonation)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "redditisfun://auth". | all |
-
-
-### [📦 `com.laurencedawson.reddit_sync.pro`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync.pro)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "http://redditsync/auth". | all |
-
-
-### [📦 `com.laurencedawson.reddit_sync.dev`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync.dev)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `change-oauth-client-id` | Changes the OAuth client ID. The OAuth application type has to be "Installed app" and the redirect URI has to be set to "http://redditsync/auth". | all |
-
-
-### [📦 `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `disable-ads` | Disables ads in HexEditor. | all |
-
-
-### [📦 `com.spotify.lite`](https://play.google.com/store/apps/details?id=com.spotify.lite)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `enable-on-demand` | Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads. | all |
-
-
-### [📦 `com.nis.app`](https://play.google.com/store/apps/details?id=com.nis.app)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `hide-ads` | Removes ads from Inshorts. | all |
-
-
-### [📦 `com.vanced.android.youtube`](https://play.google.com/store/apps/details?id=com.vanced.android.youtube)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `hide-ads` | Removes general ads. | all |
-
-
-### [📦 `com.instagram.android`](https://play.google.com/store/apps/details?id=com.instagram.android)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `hide-timeline-ads` | Removes ads from the timeline. | 275.0.0.27.98 |
-
-
-### [📦 `com.backdrops.wallpapers`](https://play.google.com/store/apps/details?id=com.backdrops.wallpapers)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `pro-unlock` | Unlocks pro-only functions. | 4.52 |
-
-
-### [📦 `de.dwd.warnapp`](https://play.google.com/store/apps/details?id=de.dwd.warnapp)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all |
-
-
-### [📦 `net.binarymode.android.irplus`](https://play.google.com/store/apps/details?id=net.binarymode.android.irplus)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-ads` | Removes all ads from the app. | all |
-
-
-### [📦 `eu.faircode.netguard`](https://play.google.com/store/apps/details?id=eu.faircode.netguard)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-broadcasts-restriction` | Enables starting/stopping NetGuard via broadcasts. | all |
-
-
-### [📦 `com.scb.phone`](https://play.google.com/store/apps/details?id=com.scb.phone)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-debugging-detection` | Removes the USB and wireless debugging checks. | all |
-
-
-### [📦 `com.google.android.apps.recorder`](https://play.google.com/store/apps/details?id=com.google.android.apps.recorder)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `remove-device-restrictions` | Removes restrictions from using the app on any device. | all |
-
-
-### [📦 `com.dci.dev.androidtwelvewidgets`](https://play.google.com/store/apps/details?id=com.dci.dev.androidtwelvewidgets)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-paid-widgets` | Unlocks paid widgets of the app | all |
-
-
-### [📦 `com.microblink.photomath`](https://play.google.com/store/apps/details?id=com.microblink.photomath)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-plus` | Unlocks plus features. | 8.20.0 |
-
-
-### [📦 `io.yuka.android`](https://play.google.com/store/apps/details?id=io.yuka.android)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-premium` | Unlocks premium features. | all |
-
-
-### [📦 `com.teslacoilsw.launcher`](https://play.google.com/store/apps/details?id=com.teslacoilsw.launcher)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all |
-
-
-### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks all professional features. | 3.4.9 |
-
-
-### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks all pro features. | all |
-
-
-### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks pro features. | 4.6377 |
-
-
-### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks all pro features. | all |
-
-
-### [📦 `com.vsco.cam`](https://play.google.com/store/apps/details?id=com.vsco.cam)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks pro features. | all |
-
-
-### [📦 `com.wakdev.apps.nfctools.se`](https://play.google.com/store/apps/details?id=com.wakdev.apps.nfctools.se)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks all pro features. | all |
-
-
-### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks pro features. | all |
-
-
-### [📦 `com.candylink.openvpn`](https://play.google.com/store/apps/details?id=com.candylink.openvpn)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks premium features. | all |
-
-
-### [📦 `tv.trakt.trakt`](https://play.google.com/store/apps/details?id=tv.trakt.trakt)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks pro features. | all |
-
-
-### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-pro` | Unlocks all pro features. | all |
-
-
-### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-themes` | Unlocks all themes that are inaccessible until a certain level is reached. | all |
-
-
-### [📦 `net.dinglisch.android.taskerm`](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)
-
-
-| 💊 Patch | 📜 Description | 🏹 Target Version |
-|:--------:|:--------------:|:-----------------:|
-| `unlock-trial` | Unlocks the trial version. | all |
-
-
-
-
-> Looking for the JSON variant of this? [Click here](patches.json).
-
-## 📝 JSON Format
-
-This section explains the JSON format for the [patches.json](patches.json) file.
-
-The file contains an array of objects, each object representing a patch. The object contains the following properties:
-
-| key | description |
-|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `name` | The name of the patch. |
-| `description` | The description of the patch. |
-| `version` | The version of the patch. |
-| `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. |
-| `options` | An array of options for this patch. |
-| `options.key` | The key of the option. |
-| `options.title` | The title of the option. |
-| `options.description` | The description of the option. |
-| `options.required` | Whether the option is required. |
-| `options.choices?` | An array of choices of the option. This may be `null` if this option has no choices. The element type of this array may be any type. It can be a `String`, `Int` or something else. |
-| `dependencies` | An array of dependencies, which are patch names. |
-| `compatiblePackages` | An array of packages compatible with this patch. |
-| `compatiblePackages.name` | The name of the package. |
-| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. |
-
-Example:
-
-```json
-[
- {
- "name": "remember-video-quality",
- "description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
- "version": "0.0.1",
- "excluded": false,
- "options": [],
- "dependencies": [
- "integrations",
- "video-id-hook"
- ],
- "compatiblePackages": [
- {
- "name": "com.google.android.youtube",
- "versions": [
- "17.22.36",
- "17.24.35",
- "17.26.35",
- "17.27.39",
- "17.28.34",
- "17.29.34",
- "17.32.35",
- "17.33.42"
- ]
- }
- ]
- },
- {
- "name": "theme",
- "description": "Enables a custom theme.",
- "version": "0.0.1",
- "excluded": 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,
- "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": []
- }
- ]
- }
-]
-```
\ No newline at end of file
+Patches for ReVanced.
diff --git a/build.gradle.kts b/build.gradle.kts
index 44d0470c..7fb48980 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,5 @@
plugins {
- kotlin("jvm") version "1.8.10"
+ kotlin("jvm") version "1.8.20"
}
group = "app.revanced"
diff --git a/gradle.properties b/gradle.properties
index 68798c58..ccad32ee 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,4 @@
+org.gradle.parallel = true
+org.gradle.caching = true
kotlin.code.style = official
-version = 2.181.0
+version = 2.182.0-dev.5
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index c1962a79..033e24c4 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2c3425d4..62f495df 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index aeb74cbb..fcb6fca1 100755
--- a/gradlew
+++ b/gradlew
@@ -130,10 +130,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
diff --git a/patches.json b/patches.json
index fd1baebe..002df280 100644
--- a/patches.json
+++ b/patches.json
@@ -1 +1 @@
-[{"name":"always-autorepeat","description":"Always repeats the playing video again.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"auto-claim-channel-points","description":"Automatically claim Channel Points.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"background-play","description":"Enables playing music in the background.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"block-audio-ads","description":"Blocks audio ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"block-embedded-ads","description":"Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker.","version":"0.0.1","excluded":false,"options":[],"dependencies":["block-video-ads","integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"block-video-ads","description":"Blocks video ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"bypass-certificate-checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"infinity://localhost\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"dbrady://relay\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"free.reddit.news","versions":[]},{"name":"reddit.news","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://baconreader.com/auth\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.onelouder.baconreader","versions":[]},{"name":"com.onelouder.baconreader.premium","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://rubenmayayo.com\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.rubenmayayo.reddit","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"redditisfun://auth\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.andrewshu.android.reddit","versions":[]},{"name":"com.andrewshu.android.redditdonation","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://redditsync/auth\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":[]},{"name":"com.laurencedawson.reddit_sync.pro","versions":[]},{"name":"com.laurencedawson.reddit_sync.dev","versions":[]}]},{"name":"change-package-name","description":"Changes the package name.","version":"0.0.1","excluded":true,"options":[{"key":"packageName","title":"Package name","description":"The name of the package to rename of the app.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"client-spoof","description":"Spoofs a patched client to allow playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-signature-verification"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"codecs-unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"comments","description":"Hides components related to comments.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"compact-header","description":"Hides the music category bar at the top of the homepage.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"copy-video-url","description":"Adds buttons in player to copy video links.","version":"0.0.1","excluded":false,"options":[],"dependencies":["copy-video-url-resource","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"custom-branding","description":"Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).","version":"0.0.1","excluded":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":"iconPath","title":"App Icon Path","description":"A path containing mipmap resource folders with icons.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"custom-video-buffer","description":"Lets you change the buffers of videos.","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"debug-mode","description":"Enables Twitch\u0027s internal debugging mode.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"disable-ads","description":"Disables ads in HexEditor.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.myprog.hexedit","versions":[]}]},{"name":"disable-ads","description":"Disables ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["DisablePiracyDetectionPatch"],"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":[]}]},{"name":"disable-auto-captions","description":"Disable forced captions from being automatically enabled.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-fullscreen-panels","description":"Disables video description and comments panel in fullscreen view.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-login-requirement","description":"Do not force login.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"disable-player-popup-panels","description":"Disables panels from appearing automatically when going into fullscreen (playlist or live chat).","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-screenshot-popup","description":"Disables the popup that shows up when taking a screenshot.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"disable-shorts-on-startup","description":"Disables playing YouTube Shorts when launching YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-switching-emoji-to-sticker-in-message-input-field","description":"Disables switching from emoji to sticker search mode in message input field","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"disable-typing-indicator","description":"Disables the indicator while typing a message","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"disable-zoom-haptics","description":"Disables haptics when zooming.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"downloads","description":"Removes download restrictions and changes the default path to download to.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"dynamic-color","description":"Replaces the default Twitter Blue with the users Material You palette.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"enable-android-debugging","description":"Enables Android debugging capabilities.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"enable-debugging","description":"Adds debugging options.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"enable-on-demand","description":"Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.lite","versions":[]}]},{"name":"exclusive-audio-playback","description":"Enables the option to play music without video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"export-all-activities","description":"Makes all app activities exportable.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"external-downloads","description":"Adds support to download and save YouTube videos using an external app.","version":"0.0.1","excluded":false,"options":[],"dependencies":["external-downloads-resource-patch","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"feed-filter","description":"Filters tiktok videos: removing ads, removing livestreams.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"fix-google-login","description":"Allows logging in with a Google account.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hdr-auto-brightness","description":"Makes the brightness of HDR videos follow the system default.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-ads","description":"Removes ads from Inshorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.nis.app","versions":[]}]},{"name":"hide-ads","description":"Hides ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["VerticalScrollPatch"],"compatiblePackages":[{"name":"com.vanced.android.youtube","versions":[]}]},{"name":"hide-ads","description":"Removes ads from the Reddit.","version":"0.0.2","excluded":false,"options":[],"dependencies":["hide-subreddit-banner","hide-comment-ads"],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-get-premium","HideAdsResourcePatch","VerticalScrollPatch","FixBackToExitGesturePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-ads","description":"Removes ads from TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hide-album-cards","description":"Hides the album cards below the artist description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-album-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-autoplay-button","description":"Hides the autoplay button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-breaking-news-shelf","description":"Hides the breaking news shelf on the homepage tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","breaking-news-shelf-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-captions-button","description":"Hides the captions button on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-cast-button","description":"Hides the cast button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-crowdfunding-box","description":"Hides the crowdfunding box between the player and video description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","crowdfunding-box-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-email-address","description":"Hides the email address in the account switcher.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-email-address-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-endscreen-cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-endscreen-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-filter-bar","description":"Hides the filter bar in video feeds.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFilterBarResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-floating-microphone-button","description":"Hides the floating microphone button which appears in search.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFloatingMicrophoneButtonResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-get-premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"hide-inbox-ads","description":"Hides ads in inbox.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"hide-info-cards","description":"Hides info cards in videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","HideInfocardsResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-layout-components","description":"Hides general layout components.","version":"0.0.1","excluded":false,"options":[],"dependencies":["LithoFilterPatch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-load-more-button","description":"Hides the button under videos that loads similar videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-load-more-button-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-player-buttons","description":"Adds the option to hide video player previous and next buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-player-overlay","description":"Hides the dark background overlay from the player when player controls are visible.","version":"0.0.2","excluded":false,"options":[],"dependencies":["HidePlayerOverlayResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-premium-navbar","description":"Removes the premium tab from the navbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"hide-recommended-users","description":"Hides recommended users.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-seekbar","description":"Hides the seekbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","SeekbarColorBytecodePatch","SeekbarPreferencesPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-shorts-components","description":"Hides components from YouTube Shorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","LithoFilterPatch","HideShortsComponentsResourcePatch","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-timeline-ads","description":"Removes ads from the timeline.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.instagram.android","versions":["275.0.0.27.98"]}]},{"name":"hide-timestamp","description":"Hides timestamp in video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-video-action-buttons","description":"Adds the options to hide action buttons under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-views-stats","description":"Hides the view stats under tweets.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideViewsBytecodePatch"],"compatiblePackages":[{"name":"com.twitter.android","versions":["9.69.1-release.0","9.71.0-release.0"]}]},{"name":"hide-watch-in-vr","description":"Hides the option to watch in VR from the player settings flyout panel.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-watermark","description":"Hides creator\u0027s watermarks on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"minimized-playback","description":"Enables minimized and background playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"minimized-playback-music","description":"Enables minimized playback on Kids music.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-video-ads","description":"Removes ads in the music player.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"navigation-buttons","description":"Adds options to hide or change navigation buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"old-quality-layout","description":"Enables the original video quality flyout in the video player settings.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","OldQualityLayoutResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"open-links-externally","description":"Open links outside of the app directly in your browser.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"playback-speed","description":"Enables the playback speed option for all videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"predictive-back-gesture","description":"Enables the predictive back gesture introduced on Android 13.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"premium-heading","description":"Shows premium branding on the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"premium-icon-reddit","description":"Unlocks premium Reddit app icons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"pro-unlock","description":"Unlocks pro-only functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}]},{"name":"promo-code-unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-cert-patch"],"compatiblePackages":[{"name":"de.dwd.warnapp","versions":[]}]},{"name":"remember-video-quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-information","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"remove-ads","description":"Removes all ads from the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":[]}]},{"name":"remove-badge-tab","description":"Removes the badge tab from the activity tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":[]}]},{"name":"remove-bootloader-detection","description":"Removes the check for an unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":[]}]},{"name":"remove-broadcasts-restriction","description":"Enables starting/stopping NetGuard via broadcasts.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"eu.faircode.netguard","versions":[]}]},{"name":"remove-debugging-detection","description":"Removes the USB and wireless debugging checks.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.scb.phone","versions":[]}]},{"name":"remove-device-restrictions","description":"Removes restrictions from using the app on any device.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.recorder","versions":[]}]},{"name":"remove-notification-badge","description":"Removes the red notification badge from the activity tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":[]}]},{"name":"remove-player-controls-background","description":"Removes the background from the video player controls.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions and unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":[]}]},{"name":"remove-screen-capture-restriction","description":"Removes the restriction of capturing audio from apps that normally wouldn\u0027t allow it.","version":"0.0.1","excluded":true,"options":[],"dependencies":["remove-screen-capture-restriction-resource-patch"],"compatiblePackages":[]},{"name":"remove-screenshot-restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"return-youtube-dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","return-youtube-dislike-resource-patch","player-type-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"sanitize-sharing-links","description":"Removes (tracking) query parameters from the URLs when sharing links.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","EnableSeekbarTappingResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"settings","description":"Adds settings menu to Twitch.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings-resource-patch"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"settings","description":"Adds ReVanced settings to TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"show-deleted-messages","description":"Shows deleted chat messages behind a clickable spoiler.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"show-seekbar","description":"Shows progress bar for all video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sim-spoof","description":"Spoofs the information which is retrieved from the sim-card.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sponsorblock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","video-information","player-type-hook","player-controls-bytecode-patch","sponsorblock-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"spoof-app-version","description":"Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"spoof-signature","description":"Spoofs the signature of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"spoof-wifi-connection","description":"Spoofs an existing Wi-Fi connection.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"spotify-theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"backgroundColor","title":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentColor","title":"Accent color","description":"The accent color (\u0027spotify green\u0027 by default). Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentPressedColor","title":"Pressed accent for the dark theme","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"swipe-controls","description":"Adds volume and brightness swipe controls.","version":"0.0.3","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","swipe-controls-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"tablet-mini-player","description":"Enables the tablet mini player layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"darkThemeBackgroundColor","title":"Background color for the dark theme","description":"The background color of the dark theme. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"lightThemeBackgroundColor","title":"Background color for the light theme","description":"The background color of the light theme. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":["litho-color-hook","SeekbarColorBytecodePatch","ThemeResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"unlock-paid-widgets","description":"Unlocks paid widgets of the app","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.dci.dev.androidtwelvewidgets","versions":[]}]},{"name":"unlock-plus","description":"Unlocks plus features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureDetectionPatch"],"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.20.0"]}]},{"name":"unlock-premium","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"io.yuka.android","versions":[]}]},{"name":"unlock-prime","description":"Unlocks Nova Prime and all functions of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.teslacoilsw.launcher","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all professional features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureVerificationPatch","LicenseValidationPatch"],"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"co.windyapp.android","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.vsco.cam","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":[]}]},{"name":"unlock-pro","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.candylink.openvpn","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"tv.trakt.trakt","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.awedea.nyx","versions":[]}]},{"name":"unlock-themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ticktick.task","versions":[]}]},{"name":"unlock-trial","description":"Unlocks the trial version.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.dinglisch.android.taskerm","versions":[]}]},{"name":"upgrade-button-remover","description":"Removes the upgrade tab from the pivot bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"vanced-microg-support","description":"Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.","version":"0.0.1","excluded":false,"options":[],"dependencies":["microg-resource-patch","hide-cast-button","client-spoof"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"vanced-microg-support","description":"Allows YouTube Music ReVanced to run without root and under a different package name.","version":"0.0.2","excluded":false,"options":[],"dependencies":["microg-resource-patch"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"video-ads","description":"Removes ads in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"video-speed","description":"Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["custom-video-speed","remember-playback-speed"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"wide-searchbar","description":"Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]}]
\ No newline at end of file
+[{"name":"always-autorepeat","description":"Always repeats the playing video again.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"auto-claim-channel-points","description":"Automatically claim Channel Points.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"background-play","description":"Enables playing music in the background.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"block-audio-ads","description":"Blocks audio ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"block-embedded-ads","description":"Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker.","version":"0.0.1","excluded":false,"options":[],"dependencies":["block-video-ads","integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"block-video-ads","description":"Blocks video ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"bypass-certificate-checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"dbrady://relay\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"free.reddit.news","versions":[]},{"name":"reddit.news","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://rubenmayayo.com\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.rubenmayayo.reddit","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"redditisfun://auth\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.andrewshu.android.reddit","versions":[]},{"name":"com.andrewshu.android.redditdonation","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://baconreader.com/auth\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.onelouder.baconreader","versions":[]},{"name":"com.onelouder.baconreader.premium","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://www.ccrama.me\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"me.ccrama.redditslide","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"infinity://localhost\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":[]}]},{"name":"change-oauth-client-id","description":"Changes the OAuth client ID. The OAuth application type has to be \"Installed app\" and the redirect URI has to be set to \"http://redditsync/auth\".","version":"0.0.0","excluded":false,"options":[{"key":"client-id","title":"OAuth client ID","description":"The Reddit OAuth client ID.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":[]},{"name":"com.laurencedawson.reddit_sync.pro","versions":[]},{"name":"com.laurencedawson.reddit_sync.dev","versions":[]}]},{"name":"change-package-name","description":"Changes the package name.","version":"0.0.1","excluded":true,"options":[{"key":"packageName","title":"Package name","description":"The name of the package to rename of the app.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"client-spoof","description":"Spoofs a patched client to allow playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-signature-verification"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"codecs-unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"comments","description":"Hides components related to comments.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"compact-header","description":"Hides the music category bar at the top of the homepage.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"copy-video-url","description":"Adds buttons in player to copy video links.","version":"0.0.1","excluded":false,"options":[],"dependencies":["copy-video-url-resource","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"custom-branding","description":"Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).","version":"0.0.1","excluded":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":"iconPath","title":"App Icon Path","description":"A path containing mipmap resource folders with icons.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"custom-video-buffer","description":"Lets you change the buffers of videos.","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"debug-mode","description":"Enables Twitch\u0027s internal debugging mode.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"disable-ads","description":"Disables ads in HexEditor.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.myprog.hexedit","versions":[]}]},{"name":"disable-ads","description":"Disables ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["DisablePiracyDetectionPatch"],"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":[]}]},{"name":"disable-auto-captions","description":"Disable forced captions from being automatically enabled.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"disable-fullscreen-panels","description":"Disables video description and comments panel in fullscreen view.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"disable-login-requirement","description":"Do not force login.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"disable-player-popup-panels","description":"Disables panels from appearing automatically when going into fullscreen (playlist or live chat).","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"disable-screenshot-popup","description":"Disables the popup that shows up when taking a screenshot.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"disable-shorts-on-startup","description":"Disables playing YouTube Shorts when launching YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"disable-switching-emoji-to-sticker-in-message-input-field","description":"Disables switching from emoji to sticker search mode in message input field","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"disable-typing-indicator","description":"Disables the indicator while typing a message","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"disable-zoom-haptics","description":"Disables haptics when zooming.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"downloads","description":"Removes download restrictions and changes the default path to download to.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"dynamic-color","description":"Replaces the default Twitter Blue with the users Material You palette.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"enable-android-debugging","description":"Enables Android debugging capabilities.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"enable-debugging","description":"Adds debugging options.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"enable-on-demand","description":"Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.lite","versions":[]}]},{"name":"exclusive-audio-playback","description":"Enables the option to play music without video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"export-all-activities","description":"Makes all app activities exportable.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"external-downloads","description":"Adds support to download and save YouTube videos using an external app.","version":"0.0.1","excluded":false,"options":[],"dependencies":["external-downloads-resource-patch","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"feed-filter","description":"Filters tiktok videos: removing ads, removing livestreams.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"fix-google-login","description":"Allows logging in with a Google account.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hdr-auto-brightness","description":"Makes the brightness of HDR videos follow the system default.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-ads","description":"Removes ads from Inshorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.nis.app","versions":[]}]},{"name":"hide-ads","description":"Removes ads from TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hide-ads","description":"Hides ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"jp.pxv.android","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["VerticalScrollPatch"],"compatiblePackages":[{"name":"com.vanced.android.youtube","versions":[]}]},{"name":"hide-ads","description":"Hides ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-get-premium","HideAdsResourcePatch","VerticalScrollPatch","FixBackToExitGesturePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-ads","description":"Removes ads from the Reddit.","version":"0.0.2","excluded":false,"options":[],"dependencies":["hide-subreddit-banner","hide-comment-ads"],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"hide-album-cards","description":"Hides the album cards below the artist description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-album-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-autoplay-button","description":"Hides the autoplay button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-breaking-news-shelf","description":"Hides the breaking news shelf on the homepage tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","breaking-news-shelf-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-captions-button","description":"Hides the captions button on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-cast-button","description":"Hides the cast button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-crowdfunding-box","description":"Hides the crowdfunding box between the player and video description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","crowdfunding-box-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-email-address","description":"Hides the email address in the account switcher.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-email-address-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-endscreen-cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-endscreen-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-filter-bar","description":"Hides the filter bar in video feeds.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFilterBarResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-floating-microphone-button","description":"Hides the floating microphone button which appears in search.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFloatingMicrophoneButtonResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-get-premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"hide-inbox-ads","description":"Hides ads in inbox.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"hide-info-cards","description":"Hides info cards in videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","HideInfocardsResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-layout-components","description":"Hides general layout components.","version":"0.0.1","excluded":false,"options":[],"dependencies":["LithoFilterPatch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-load-more-button","description":"Hides the button under videos that loads similar videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-load-more-button-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-player-buttons","description":"Adds the option to hide video player previous and next buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-player-overlay","description":"Hides the dark background overlay from the player when player controls are visible.","version":"0.0.2","excluded":false,"options":[],"dependencies":["HidePlayerOverlayResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-premium-navbar","description":"Removes the premium tab from the navbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"hide-recommended-users","description":"Hides recommended users.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-seekbar","description":"Hides the seekbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","SeekbarColorBytecodePatch","SeekbarPreferencesPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-shorts-components","description":"Hides components from YouTube Shorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","LithoFilterPatch","HideShortsComponentsResourcePatch","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-timeline-ads","description":"Removes ads from the timeline.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.instagram.android","versions":["275.0.0.27.98"]}]},{"name":"hide-timestamp","description":"Hides timestamp in video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-video-action-buttons","description":"Adds the options to hide action buttons under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-views-stats","description":"Hides the view stats under tweets.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideViewsBytecodePatch"],"compatiblePackages":[{"name":"com.twitter.android","versions":["9.69.1-release.0","9.71.0-release.0"]}]},{"name":"hide-watch-in-vr","description":"Hides the option to watch in VR from the player settings flyout panel.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"hide-watermark","description":"Hides creator\u0027s watermarks on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"minimized-playback","description":"Enables minimized and background playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"minimized-playback-music","description":"Enables minimized playback on Kids music.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-video-ads","description":"Removes ads in the music player.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"navigation-buttons","description":"Adds options to hide or change navigation buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"old-video-quality-menu","description":"Shows the old video quality with the advanced video quality options instead of the new one.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","OldVideoQualityMenuResourcePatch","LithoFilterPatch","BottomSheetHookPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.20.39","18.23.35"]}]},{"name":"open-links-externally","description":"Open links outside of the app directly in your browser.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"playback-speed","description":"Enables the playback speed option for all videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"predictive-back-gesture","description":"Enables the predictive back gesture introduced on Android 13.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"premium-heading","description":"Shows premium branding on the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"premium-icon-reddit","description":"Unlocks premium Reddit app icons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"pro-unlock","description":"Unlocks pro-only functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}]},{"name":"promo-code-unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-cert-patch"],"compatiblePackages":[{"name":"de.dwd.warnapp","versions":[]}]},{"name":"remember-video-quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-information","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.19.35","18.20.39","18.23.35"]}]},{"name":"remove-ads","description":"Removes all ads from the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":[]}]},{"name":"remove-badge-tab","description":"Removes the badge tab from the activity tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":[]}]},{"name":"remove-bootloader-detection","description":"Removes the check for an unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":[]}]},{"name":"remove-broadcasts-restriction","description":"Enables starting/stopping NetGuard via broadcasts.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"eu.faircode.netguard","versions":[]}]},{"name":"remove-debugging-detection","description":"Removes the USB and wireless debugging checks.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.scb.phone","versions":[]}]},{"name":"remove-device-restrictions","description":"Removes restrictions from using the app on any device.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.recorder","versions":[]}]},{"name":"remove-notification-badge","description":"Removes the red notification badge from the activity tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":[]}]},{"name":"remove-player-controls-background","description":"Removes the background from the video player controls.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":[]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions and unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"remove-screen-capture-restriction","description":"Removes the restriction of capturing audio from apps that normally wouldn\u0027t allow it.","version":"0.0.1","excluded":true,"options":[],"dependencies":["remove-screen-capture-restriction-resource-patch"],"compatiblePackages":[]},{"name":"remove-screenshot-restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"return-youtube-dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","return-youtube-dislike-resource-patch","player-type-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"sanitize-sharing-links","description":"Removes (tracking) query parameters from the URLs when sharing links.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","EnableSeekbarTappingResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"settings","description":"Adds ReVanced settings to TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"settings","description":"Adds settings menu to Twitch.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings-resource-patch"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"show-deleted-messages","description":"Shows deleted chat messages behind a clickable spoiler.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1"]}]},{"name":"show-seekbar","description":"Shows progress bar for all video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sim-spoof","description":"Spoofs the information which is retrieved from the sim-card.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sponsorblock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","video-information","player-type-hook","player-controls-bytecode-patch","sponsorblock-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"spoof-app-version","description":"Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"spoof-signature","description":"Spoofs the signature of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"spoof-wifi-connection","description":"Spoofs an existing Wi-Fi connection.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"spotify-theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"backgroundColor","title":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentColor","title":"Accent color","description":"The accent color (\u0027spotify green\u0027 by default). Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentPressedColor","title":"Pressed accent for the dark theme","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"swipe-controls","description":"Adds volume and brightness swipe controls.","version":"0.0.3","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","swipe-controls-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"tablet-mini-player","description":"Enables the tablet mini player layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"darkThemeBackgroundColor","title":"Background color for the dark theme","description":"The background color of the dark theme. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"lightThemeBackgroundColor","title":"Background color for the light theme","description":"The background color of the light theme. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":["litho-color-hook","SeekbarColorBytecodePatch","ThemeResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"unlock-paid-widgets","description":"Unlocks paid widgets of the app","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.dci.dev.androidtwelvewidgets","versions":[]}]},{"name":"unlock-plus","description":"Unlocks plus features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureDetectionPatch"],"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.20.0"]}]},{"name":"unlock-premium","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"io.yuka.android","versions":[]}]},{"name":"unlock-prime","description":"Unlocks Nova Prime and all functions of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.teslacoilsw.launcher","versions":[]}]},{"name":"unlock-pro","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.candylink.openvpn","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.awedea.nyx","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"co.windyapp.android","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"tv.trakt.trakt","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureVerificationPatch","LicenseValidationPatch"],"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}]},{"name":"unlock-pro","description":"Unlocks all professional features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.vsco.cam","versions":[]}]},{"name":"unlock-themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ticktick.task","versions":[]}]},{"name":"unlock-trial","description":"Unlocks the trial version.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.dinglisch.android.taskerm","versions":[]}]},{"name":"upgrade-button-remover","description":"Removes the upgrade tab from the pivot bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"vanced-microg-support","description":"Allows YouTube Music ReVanced to run without root and under a different package name.","version":"0.0.2","excluded":false,"options":[],"dependencies":["microg-resource-patch"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"vanced-microg-support","description":"Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.","version":"0.0.1","excluded":false,"options":[],"dependencies":["microg-resource-patch","hide-cast-button","client-spoof"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"video-ads","description":"Removes ads in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]},{"name":"video-speed","description":"Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["custom-video-speed","remember-playback-speed"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.20.39","18.23.35"]}]},{"name":"wide-searchbar","description":"Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35"]}]}]
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt b/src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt
index 62667a33..dfb57d92 100644
--- a/src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt
+++ b/src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt
@@ -19,7 +19,7 @@ internal interface PatchesFileGenerator {
).loadPatches().also {
if (it.isEmpty()) throw IllegalStateException("No patches found")
}.let { bundle ->
- arrayOf(JsonGenerator(), ReadmeGenerator()).forEach { it.generate(bundle) }
+ arrayOf(JsonGenerator()).forEach { it.generate(bundle) }
}
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt b/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt
deleted file mode 100644
index e8a951ea..00000000
--- a/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-package app.revanced.meta
-
-import app.revanced.patcher.data.Context
-import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
-import app.revanced.patcher.extensions.PatchExtensions.description
-import app.revanced.patcher.extensions.PatchExtensions.patchName
-import app.revanced.patcher.patch.Patch
-import com.unascribed.flexver.FlexVerComparator
-import java.io.File
-
-internal class ReadmeGenerator : PatchesFileGenerator {
- private companion object {
- private const val TABLE_HEADER =
- "| \uD83D\uDC8A Patch | \uD83D\uDCDC Description | \uD83C\uDFF9 Target Version |\n" +
- "|:--------:|:--------------:|:-----------------:|"
- }
-
- override fun generate(bundle: PatchBundlePatches) {
- val output = StringBuilder()
-
- mutableMapOf>>>()
- .apply {
- for (patch in bundle) {
- patch.compatiblePackages?.forEach { pkg ->
- if (!contains(pkg.name)) put(pkg.name, mutableListOf())
- this[pkg.name]!!.add(patch)
- }
- }
- }
- .entries
- .sortedByDescending { it.value.size }
- .forEach { (`package`, patches) ->
- val mostCommonVersion = buildMap {
- patches.forEach { patch ->
- patch.compatiblePackages?.single { compatiblePackage -> compatiblePackage.name == `package` }?.versions?.let {
- it.forEach { version -> merge(version, 1, Integer::sum) }
- }
- }
- }.let { commonMap ->
- commonMap.maxByOrNull { it.value }?.value?.let {
- commonMap.entries.filter { mostCommon -> mostCommon.value == it }
- .maxOfWith(FlexVerComparator::compare, Map.Entry::key)
- } ?: "all"
- }
-
- output.apply {
- appendLine("### [\uD83D\uDCE6 `${`package`}`](https://play.google.com/store/apps/details?id=${`package`})")
- appendLine("\n")
- appendLine(TABLE_HEADER)
- patches.forEach { patch ->
- val recommendedPatchVersion = if (
- patch.compatiblePackages?.single { it.name == `package` }?.versions?.isNotEmpty() == true
- ) mostCommonVersion else "all"
-
- appendLine(
- "| `${patch.patchName}` " +
- "| ${patch.description} " +
- "| $recommendedPatchVersion |"
- )
- }
- appendLine(" \n")
- }
- }
-
- StringBuilder(File("README-template.md").readText())
- .replace(Regex("\\{\\{\\s?table\\s?}}"), output.toString())
- .let(File("README.md")::writeText)
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/pixiv/ads/fingerprints/IsNotPremiumFingerprint.kt b/src/main/kotlin/app/revanced/patches/pixiv/ads/fingerprints/IsNotPremiumFingerprint.kt
new file mode 100644
index 00000000..453ec7fe
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/pixiv/ads/fingerprints/IsNotPremiumFingerprint.kt
@@ -0,0 +1,21 @@
+package app.revanced.patches.pixiv.ads.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.AccessFlags
+
+
+object IsNotPremiumFingerprint : MethodFingerprint(
+ "V",
+ AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
+ listOf("L"),
+ strings = listOf("pixivAccountManager"),
+ customFingerprint = custom@{ _, classDef ->
+ // The "isNotPremium" method is the only method in the class.
+ if (classDef.virtualMethods.count() != 1) return@custom false
+
+ classDef.virtualMethods.first().let { isNotPremiumMethod ->
+ isNotPremiumMethod.parameterTypes.size == 0 && isNotPremiumMethod.returnType == "Z"
+ }
+ }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/pixiv/ads/patch/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/pixiv/ads/patch/HideAdsPatch.kt
new file mode 100644
index 00000000..4b072f32
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/pixiv/ads/patch/HideAdsPatch.kt
@@ -0,0 +1,33 @@
+package app.revanced.patches.pixiv.ads.patch
+
+import app.revanced.extensions.toErrorResult
+import app.revanced.patcher.annotation.*
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.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.pixiv.ads.fingerprints.IsNotPremiumFingerprint
+
+@Patch
+@Name("hide-ads")
+@Description("Hides ads.")
+@Compatibility([Package("jp.pxv.android")])
+@Version("0.0.1")
+class HideAdsPatch : BytecodePatch(listOf(IsNotPremiumFingerprint)) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ // Always return false in the "isNotPremium" method which normally returns !this.accountManager.isPremium.
+ // However, this is not the method that controls the user's premium status.
+ // Instead, this method is used to determine whether ads should be shown.
+ IsNotPremiumFingerprint.result?.mutableClass?.virtualMethods?.first()?.addInstructions(
+ 0,
+ """
+ const/4 v0, 0x0
+ return v0
+ """
+ ) ?: return IsNotPremiumFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/fingerprints/GetClientIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/fingerprints/GetClientIdFingerprint.kt
new file mode 100644
index 00000000..9caed985
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/fingerprints/GetClientIdFingerprint.kt
@@ -0,0 +1,11 @@
+package app.revanced.patches.reddit.customclients.slide.api.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+
+object GetClientIdFingerprint : MethodFingerprint(
+ customFingerprint = custom@{ methodDef, classDef ->
+ if (!classDef.type.endsWith("Credentials;")) return@custom false
+
+ methodDef.name == "getClientId"
+ }
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/patch/ChangeOAuthClientIdPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/patch/ChangeOAuthClientIdPatch.kt
new file mode 100644
index 00000000..90a9372f
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/slide/api/patch/ChangeOAuthClientIdPatch.kt
@@ -0,0 +1,36 @@
+package app.revanced.patches.reddit.customclients.slide.api.patch
+
+import app.revanced.patcher.annotation.Compatibility
+import app.revanced.patcher.annotation.Description
+import app.revanced.patcher.annotation.Package
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patches.reddit.customclients.AbstractChangeOAuthClientIdPatch
+import app.revanced.patches.reddit.customclients.ChangeOAuthClientIdPatchAnnotation
+import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.GetClientIdFingerprint
+
+@ChangeOAuthClientIdPatchAnnotation
+@Description("Changes the OAuth client ID. " +
+ "The OAuth application type has to be \"Installed app\" " +
+ "and the redirect URI has to be set to \"http://www.ccrama.me\".")
+@Compatibility([Package("me.ccrama.redditslide")])
+class ChangeOAuthClientIdPatch : AbstractChangeOAuthClientIdPatch(
+ "http://www.ccrama.me", Options, listOf(GetClientIdFingerprint)
+) {
+ override fun List.patch(context: BytecodeContext): PatchResult {
+ first().mutableMethod.addInstructions(
+ 0,
+ """
+ const-string v0, "$clientId"
+ return-object v0
+ """
+ )
+
+ return PatchResultSuccess()
+ }
+
+ companion object Options : AbstractChangeOAuthClientIdPatch.Options.ChangeOAuthClientIdOptionsContainer()
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt
index 798560a7..5f90c501 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.ad.general.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideAdsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/annotations/HideGetPremiumCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/annotations/HideGetPremiumCompatibility.kt
index 7f395874..f17ebada 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/annotations/HideGetPremiumCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/annotations/HideGetPremiumCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.ad.getpremium.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideGetPremiumCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt
index 6713227a..9226b6f4 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.ad.video.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class VideoAdsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt
index fc46729a..93058c89 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.interaction.copyvideourl.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class CopyVideoUrlCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/ExternalDownloadsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/ExternalDownloadsCompatibility.kt
index 7dc840c6..be32f73c 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/ExternalDownloadsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/ExternalDownloadsCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.interaction.downloads.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class ExternalDownloadsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt
index 56a7b689..cd1b8ca0 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.interaction.seekbar.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class SeekbarTappingCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt
index feaa5eff..ad2ec177 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.interaction.swipecontrols.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class SwipeControlsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt
index c03a3e7f..81fb60d3 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.autocaptions.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class AutoCaptionsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt
index 11272535..1c521c54 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.action.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideButtonsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt
index 278fb0c2..bb95ff03 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.autoplay.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class AutoplayButtonCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt
index 849d2e18..fc1e112a 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.captions.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideCaptionsButtonCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt
index e298888c..393ac136 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.navigation.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class NavigationButtonsCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt
index 1f20ff2f..15330096 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.player.hide.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HidePlayerButtonsCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt
index 1523ca1c..889695ea 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.albumcards.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class AlbumCardsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt
index af446cfe..635820ab 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.breakingnews.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class BreakingNewsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt
index 27f8151f..6d8b3b3e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.comments.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideCommentsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt
index f6776877..fe6894aa 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.crowdfundingbox.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class CrowdfundingBoxCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt
index 47d27801..20627589 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.endscreencards.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideEndscreenCardsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt
index e45cafd7..95aa29f6 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.filterbar.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideFilterBar
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt
index 8ab0a1e5..b5f04f78 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.floatingmicrophone.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideFloatingMicrophoneButtonCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/annotations/HideLayoutComponentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/annotations/HideLayoutComponentsCompatibility.kt
index 926b9792..a685bf3e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/annotations/HideLayoutComponentsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/annotations/HideLayoutComponentsCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.layout.hide.general.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideLayoutComponentsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ConvertElementToFlatBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ConvertElementToFlatBufferFingerprint.kt
new file mode 100644
index 00000000..a9ada6da
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ConvertElementToFlatBufferFingerprint.kt
@@ -0,0 +1,9 @@
+package app.revanced.patches.youtube.layout.hide.general.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object ConvertElementToFlatBufferFingerprint : MethodFingerprint(
+ strings = listOf("Failed to convert Element to Flatbuffers: %s"),
+ opcodes = listOf(Opcode.IGET_OBJECT) // Patched at this opcodes index
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt
index 203d22ca..00a0fd81 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt
@@ -1,18 +1,24 @@
package app.revanced.patches.youtube.layout.hide.general.patch
+import app.revanced.extensions.toErrorResult
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.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
-import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.shared.settings.preference.impl.TextPreference
import app.revanced.patches.youtube.layout.hide.general.annotations.HideLayoutComponentsCompatibility
+import app.revanced.patches.youtube.layout.hide.general.fingerprints.ConvertElementToFlatBufferFingerprint
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen
@@ -23,8 +29,10 @@ import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.P
@DependsOn([LithoFilterPatch::class, SettingsPatch::class])
@HideLayoutComponentsCompatibility
@Version("0.0.1")
-class HideLayoutComponentsPatch : ResourcePatch {
- override fun execute(context: ResourceContext): PatchResult {
+class HideLayoutComponentsPatch : BytecodePatch(
+ listOf(ConvertElementToFlatBufferFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_hide_gray_separator",
@@ -237,6 +245,35 @@ class HideLayoutComponentsPatch : ResourcePatch {
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
+ // region Mix playlists
+
+ ConvertElementToFlatBufferFingerprint.result?.let {
+ val returnEmptyComponentIndex = it.scanResult.stringsScanResult!!.matches.first().index + 2
+
+ it.mutableMethod.apply {
+ // The last virtual register (not parameter). Used to store the byte array
+ // that may contain information about a mix playlist.
+ val freeRegister = (implementation!!.registerCount - 1) - parameterTypes.size - 1
+
+ // Check if the byte array contains anything about a mix playlist.
+ addInstructionsWithLabels(
+ it.scanResult.patternScanResult!!.startIndex,
+ """
+ invoke-static {v$freeRegister}, $FILTER_CLASS_DESCRIPTOR->filterMixPlaylists([B)Z
+ move-result v$freeRegister
+ if-nez v$freeRegister, :return_empty_component
+ """,
+ ExternalLabel("return_empty_component", getInstruction(returnEmptyComponentIndex))
+ )
+
+ // Move the byte array to a free register.
+ addInstruction(0, "move-object/from16 v$freeRegister, p3")
+ }
+
+ } ?: return ConvertElementToFlatBufferFingerprint.toErrorResult()
+
+ // endregion
+
return PatchResultSuccess()
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt
index 8a71676e..520f038f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.infocards.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideInfocardsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt
index 5c580599..a9c4bcea 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.layout.hide.loadmorebutton.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideLoadMoreButtonCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt
index 27abf272..3d719339 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.personalinformation.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideEmailAddressCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt
index c22588a2..1325bee9 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt
@@ -1,12 +1,13 @@
package app.revanced.patches.youtube.layout.hide.player.overlay.bytecode.fingerprints
+import app.revanced.extensions.containsConstantInstructionValue
import app.revanced.patcher.extensions.or
-import app.revanced.util.patch.LiteralValueFingerprint
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch.HidePlayerOverlayResourcePatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
-object CreatePlayerOverviewFingerprint : LiteralValueFingerprint(
+object CreatePlayerOverviewFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(
@@ -15,5 +16,8 @@ object CreatePlayerOverviewFingerprint : LiteralValueFingerprint(
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST
),
- literal = HidePlayerOverlayResourcePatch.scrimOverlayId
+ customFingerprint = { methodDef, _ ->
+ methodDef.definingClass.endsWith("YouTubeControlsOverlay;")
+ && methodDef.containsConstantInstructionValue(HidePlayerOverlayResourcePatch.scrimOverlayId)
+ }
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt
index 560e17a8..784fa861 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.seekbar.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideSeekbarCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt
index a058e84c..e434846d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.shorts.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideShortsComponentsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt
index c3f3c777..baa9be5f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.time.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideTimeCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt
index 9eba5cc7..e03bee70 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.watchinvr.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class WatchInVRCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt
index 8d11da21..687b5065 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.watermark.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideWatermarkCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt
index 86a2865c..11dbf884 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.panels.fullscreen.remove.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class FullscreenPanelsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt
index c05d454b..e6da7990 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.panels.popup.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class PlayerPopupPanelsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/annotations/PlayerControlsBackgroundCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/annotations/PlayerControlsBackgroundCompatibility.kt
index ac2062c5..d7e6490f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/annotations/PlayerControlsBackgroundCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/annotations/PlayerControlsBackgroundCompatibility.kt
@@ -2,6 +2,6 @@ package app.revanced.patches.youtube.layout.player.background.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class PlayerControlsBackgroundCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt
index aa0f3fcc..5f3dd157 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class ReturnYouTubeDislikeCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt
index 199f1488..c5955c0f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt
@@ -21,14 +21,11 @@ object TextComponentAtomicReferenceFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.MOVE_OBJECT, // CharSequence reference, and control flow label. Insert code here.
- Opcode.INVOKE_VIRTUAL,
+ null, // invoke-interface or invoke-virtual
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
- Opcode.INVOKE_VIRTUAL,
+ null, // invoke-interface or invoke-virtual
Opcode.MOVE_RESULT_OBJECT,
Opcode.GOTO,
- Opcode.CONST_4,
- Opcode.INVOKE_VIRTUAL_RANGE,
- Opcode.MOVE_RESULT_OBJECT,
)
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt
index eee7ab2a..7e4d3141 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt
@@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
/**
- * Resolves against the same method that [TextComponentContextFingerprint] resolves to.
+ * Resolves against the same class that [TextComponentConstructorFingerprint] resolves to.
*/
object TextComponentContextFingerprint : MethodFingerprint(
returnType = "L",
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt
index 75d3373e..1fe97fe0 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.searchbar.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class WideSearchbarCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt
index f805334f..7eefbbd5 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.sponsorblock.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class SponsorBlockCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt
index c64f1774..04740e6f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt
@@ -3,7 +3,7 @@ package app.revanced.patches.youtube.layout.spoofappversion.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class SpoofAppVersionCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt
index 72b51685..9b202279 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.startupshortsreset.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class StartupShortsResetCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt
index ded1563e..4284c94d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.tabletminiplayer.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class TabletMiniPlayerCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt
index e43e1770..f2210f76 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt
@@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode
object MiniPlayerOverrideFingerprint : MethodFingerprint(
"Z", AccessFlags.STATIC or AccessFlags.PUBLIC,
- listOf("L"),
+ listOf("Landroid/content/Context;"),
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideParentFingerprint.kt
index a4180746..df535223 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideParentFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideParentFingerprint.kt
@@ -3,5 +3,5 @@ package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object MiniPlayerOverrideParentFingerprint : MethodFingerprint(
- strings = listOf("Possible Context wrapper loop - chain of wrappers larger than 10000")
+ strings = listOf("Unset or unknown Input OneOf case for dynamic input")
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt
index ab04bfe8..b4b62674 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.autorepeat.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class AutoRepeatCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/bottomsheet/hook/fingerprints/CreateBottomSheetFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/bottomsheet/hook/fingerprints/CreateBottomSheetFingerprint.kt
new file mode 100644
index 00000000..70c04aa3
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/bottomsheet/hook/fingerprints/CreateBottomSheetFingerprint.kt
@@ -0,0 +1,13 @@
+package app.revanced.patches.youtube.misc.bottomsheet.hook.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.video.videoqualitymenu.patch.OldVideoQualityMenuResourcePatch
+import app.revanced.util.patch.LiteralValueFingerprint
+import org.jf.dexlib2.AccessFlags
+
+object CreateBottomSheetFingerprint : LiteralValueFingerprint(
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+ parameters = listOf("L"),
+ returnType = "Landroid/widget/LinearLayout;",
+ literal = OldVideoQualityMenuResourcePatch.bottomSheetMargins
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/bottomsheet/hook/patch/BottomSheetHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/bottomsheet/hook/patch/BottomSheetHookPatch.kt
new file mode 100644
index 00000000..d72b974e
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/bottomsheet/hook/patch/BottomSheetHookPatch.kt
@@ -0,0 +1,43 @@
+package app.revanced.patches.youtube.misc.bottomsheet.hook.patch
+
+import app.revanced.extensions.toErrorResult
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patches.youtube.misc.bottomsheet.hook.fingerprints.CreateBottomSheetFingerprint
+import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
+import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
+
+@DependsOn([IntegrationsPatch::class])
+class BottomSheetHookPatch : BytecodePatch(
+ listOf(CreateBottomSheetFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ CreateBottomSheetFingerprint.result?.let {
+ it.mutableMethod.apply {
+ val returnLinearLayoutIndex = implementation!!.instructions.lastIndex
+ val linearLayoutRegister = getInstruction(returnLinearLayoutIndex).registerA
+
+ addHook = { classDescriptor ->
+ addInstruction(
+ returnLinearLayoutIndex,
+ "invoke-static { v$linearLayoutRegister }, " +
+ "${classDescriptor}->" +
+ "onFlyoutMenuCreate(Landroid/widget/LinearLayout;)V"
+ )
+ }
+ }
+ } ?: return CreateBottomSheetFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+
+ internal companion object {
+ internal lateinit var addHook: (String) -> Unit
+ private set
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt
index 8a470352..bce548f1 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class FixBackToExitGestureCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt
index 13e9c51b..24c49518 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.fix.playback.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class ClientSpoofCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt
index 0bdca1b8..9de9f53c 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.integrations.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class IntegrationsCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt
index 9485b3ef..233b8ce6 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.links.open.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class OpenLinksExternallyCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferFingerprint.kt
deleted file mode 100644
index 9e099793..00000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferFingerprint.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package app.revanced.patches.youtube.misc.litho.filter.fingerprints
-
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.Opcode
-
-object ProtobufBufferFingerprint : MethodFingerprint(
- opcodes = listOf(
- Opcode.IGET_OBJECT, // References the field required below.
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- Opcode.IF_NEZ,
- Opcode.CONST_4,
- Opcode.GOTO,
- Opcode.CHECK_CAST, // Casts the referenced field to a specific type that stores the protobuf buffer.
- Opcode.INVOKE_VIRTUAL
- )
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferReferenceFingerprint.kt
new file mode 100644
index 00000000..aeecb9e2
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferReferenceFingerprint.kt
@@ -0,0 +1,18 @@
+package app.revanced.patches.youtube.misc.litho.filter.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 ProtobufBufferReferenceFingerprint : MethodFingerprint(
+ returnType = "V",
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+ parameters = listOf("I", "Ljava/nio/ByteBuffer;"),
+ opcodes = listOf(
+ Opcode.IPUT,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.MOVE_RESULT,
+ Opcode.SUB_INT_2ADDR
+ )
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt
index 2b709072..59848db0 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt
@@ -4,50 +4,110 @@ import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
+import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.*
+import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
+import org.jf.dexlib2.immutable.ImmutableField
import java.io.Closeable
@DependsOn([IntegrationsPatch::class])
@Description("Hooks the method which parses the bytes into a ComponentContext to filter components.")
@Version("0.0.1")
class LithoFilterPatch : BytecodePatch(
- listOf(ComponentContextParserFingerprint, LithoFilterFingerprint)
+ listOf(ComponentContextParserFingerprint, LithoFilterFingerprint, ProtobufBufferReferenceFingerprint)
), Closeable {
+ /**
+ * The following patch inserts a hook into the method that parses the bytes into a ComponentContext.
+ * This method contains a StringBuilder object that represents the pathBuilder of the component.
+ * The pathBuilder is used to filter components by their path.
+ *
+ * Additionally, the method contains a reference to the components identifier.
+ * The identifier is used to filter components by their identifier.
+ *
+ * In addition to that, a static field is added to the class of this method. (See protobufBufferField).
+ * This field holds a reference to the protobuf buffer object.
+ * The field is being set in another method that holds a reference to the protobuf buffer object.
+ * The object contains a large byte array that represents the component tree.
+ * This byte array is searched for strings that indicate the current component.
+ *
+ * The following pseudo code shows how the patch works:
+ *
+ * class ComponentContextParser {
+ * public static ByteBuffer buffer; // Inserted by this patch.
+ *
+ * public ComponentContext parseBytesToComponentContext(...) {
+ * ...
+ * if (filter(identifier, pathBuilder, buffer)); // Inserted by this patch.
+ * return emptyComponent;
+ * ...
+ * }
+ * }
+ *
+ * class SomeOtherClass {
+ * // Called before ComponentContextParser.parseBytesToComponentContext method.
+ * public void someOtherMethod(ByteBuffer byteBuffer) {
+ * ComponentContextParser.buffer = byteBuffer; // Inserted by this patch.
+ * ...
+ * }
+ * }
+ */
override fun execute(context: BytecodeContext): PatchResult {
ComponentContextParserFingerprint.result?.also {
arrayOf(
EmptyComponentBuilderFingerprint,
- ReadComponentIdentifierFingerprint,
- ProtobufBufferFingerprint
+ ReadComponentIdentifierFingerprint
).forEach { fingerprint ->
if (fingerprint.resolve(context, it.mutableMethod, it.mutableClass)) return@forEach
return fingerprint.toErrorResult()
}
- }?.let { result ->
+ }?.let { bytesToComponentContextMethod ->
+ // region Add a static field that holds a reference to the protobuf buffer object.
+ val protobufBufferField = ImmutableField(
+ bytesToComponentContextMethod.mutableClass.type,
+ "buffer",
+ "Ljava/nio/ByteBuffer;",
+ AccessFlags.PUBLIC or AccessFlags.STATIC,
+ null,
+ null,
+ null
+ ).toMutable()
+ bytesToComponentContextMethod.mutableClass.staticFields.add(protobufBufferField)
+
+ // Set the field with the reference to the protobuf buffer object.
+ ProtobufBufferReferenceFingerprint.result
+ ?.mutableMethod?.addInstruction(0, "sput-object p2, $protobufBufferField")
+ ?: return ProtobufBufferReferenceFingerprint.toErrorResult()
+
+ // endregion
+
+ // region Hook the method that parses bytes into a ComponentContext.
+
val builderMethodIndex = EmptyComponentBuilderFingerprint.patternScanEndIndex
val emptyComponentFieldIndex = builderMethodIndex + 2
- result.mutableMethod.apply {
- val insertHookIndex = result.scanResult.patternScanResult!!.endIndex
+ bytesToComponentContextMethod.mutableMethod.apply {
+ val insertHookIndex = bytesToComponentContextMethod.scanResult.patternScanResult!!.endIndex
- // region Get free registers that this patch uses
+ // region Get free registers that this patch uses.
// Registers are overwritten right after they are used in this patch, therefore free to clobber.
val freeRegistersInstruction = getInstruction(insertHookIndex - 2)
@@ -64,7 +124,7 @@ class LithoFilterPatch : BytecodePatch(
// endregion
- // region Get references that this patch needs
+ // region Get references that this patch needs.
val builderMethodDescriptor = getInstruction(builderMethodIndex).descriptor
val emptyComponentFieldDescriptor = getInstruction(emptyComponentFieldIndex).descriptor
@@ -72,34 +132,18 @@ class LithoFilterPatch : BytecodePatch(
val identifierRegister =
getInstruction(ReadComponentIdentifierFingerprint.patternScanEndIndex).registerA
- // Parameter that holds a ref to a type with a field that ref the protobuf buffer object.
- val protobufParameterNumber = 3
-
- // Get the field that stores an protobuf buffer required below.
- val protobufBufferRefTypeRefFieldDescriptor =
- getInstruction(ProtobufBufferFingerprint.patternScanStartIndex).descriptor
- val protobufBufferRefTypeDescriptor =
- getInstruction(ProtobufBufferFingerprint.patternScanEndIndex - 1).descriptor
- val protobufBufferFieldDescriptor = "$protobufBufferRefTypeDescriptor->b:Ljava/nio/ByteBuffer;"
-
// endregion
- // region Patch the method
+ // region Patch the method.
// Insert the instructions that are responsible
// to return an EmptyComponent instead of the original component if the filter method returns false.
addInstructionsWithLabels(
insertHookIndex,
"""
- # Get the protobuf buffer object.
-
- move-object/from16 v$free1, p$protobufParameterNumber
- iget-object v$free1, v$free1, $protobufBufferRefTypeRefFieldDescriptor
- check-cast v$free1, $protobufBufferRefTypeDescriptor
-
- # Register "free" now holds the protobuf buffer object
+ # Register "free1" holds the protobuf buffer object
- iget-object v$free1, v$free1, $protobufBufferFieldDescriptor
+ sget-object v$free1, $protobufBufferField
# Invoke the filter method.
@@ -119,6 +163,8 @@ class LithoFilterPatch : BytecodePatch(
)
// endregion
}
+
+ // endregion
} ?: return ComponentContextParserFingerprint.toErrorResult()
LithoFilterFingerprint.result?.mutableMethod?.apply {
@@ -150,9 +196,6 @@ class LithoFilterPatch : BytecodePatch(
private val MethodFingerprint.patternScanEndIndex
get() = patternScanResult.endIndex
- private val MethodFingerprint.patternScanStartIndex
- get() = patternScanResult.startIndex
-
private val Instruction.descriptor
get() = (this as ReferenceInstruction).reference.toString()
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt
index 352ed374..30383fbf 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.microg.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class MicroGPatchCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt
index 88bff32b..782a7709 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.minimizedplayback.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class MinimizedPlaybackCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt
index ca676e7a..a184fe77 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt
@@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
- returnType = "L",
+ returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsParentFingerprint.kt
index 59754a7f..180547a2 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsParentFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsParentFingerprint.kt
@@ -8,7 +8,8 @@ import org.jf.dexlib2.AccessFlags
* Class fingerprint for [MinimizedPlaybackSettingsFingerprint]
*/
object MinimizedPlaybackSettingsParentFingerprint : MethodFingerprint(
- accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
- parameters = listOf("Landroid/content/Context;", "Landroid/support/v4/media/session/MediaSessionCompat"),
- strings = listOf("sessionToken must not be null")
+ accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
+ returnType = "I",
+ parameters = listOf(),
+ strings = listOf("BiometricManager", "Failure in canAuthenticate(). FingerprintManager was null.")
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt
index 296b6477..311f4850 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.playercontrols.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class PlayerControlsCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt
index 89a6fa3d..f65f8170 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.playeroverlay.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class PlayerOverlaysHookCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt
index dff4ca51..8630c376 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.playertype.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class PlayerTypeHookCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt
index 628499d6..d1c317de 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt
@@ -4,6 +4,6 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
// TODO: delete this
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class CustomVideoBufferCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt
index 29e7da07..85bb22dc 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.video.hdrbrightness.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HDRBrightnessCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt
index 2ff6163d..1b52f4df 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.video.information.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class VideoInformationCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutPatch.kt
deleted file mode 100644
index 7f9d1b77..00000000
--- a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutPatch.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package app.revanced.patches.youtube.video.oldqualitylayout.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.InstructionExtensions.addInstruction
-import app.revanced.patcher.patch.BytecodePatch
-import app.revanced.patcher.patch.PatchResult
-import app.revanced.patcher.patch.PatchResultSuccess
-import app.revanced.patcher.patch.annotations.DependsOn
-import app.revanced.patcher.patch.annotations.Patch
-import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
-import app.revanced.patches.youtube.video.oldqualitylayout.annotations.OldQualityLayoutCompatibility
-import app.revanced.patches.youtube.video.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint
-import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
-
-@Patch
-@DependsOn([IntegrationsPatch::class, OldQualityLayoutResourcePatch::class])
-@Name("old-quality-layout")
-@Description("Enables the original video quality flyout in the video player settings.")
-@OldQualityLayoutCompatibility
-@Version("0.0.1")
-class OldQualityLayoutPatch : BytecodePatch(listOf(QualityMenuViewInflateFingerprint)) {
- override fun execute(context: BytecodeContext): PatchResult {
- val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!!
- val method = inflateFingerprintResult.mutableMethod
- val instructions = method.implementation!!.instructions
-
- // at this index the listener is added to the list view
- val listenerInvokeRegister = instructions.size - 1 - 1
-
- // get the register which stores the quality menu list view
- val onItemClickViewRegister = (instructions[listenerInvokeRegister] as FiveRegisterInstruction).registerC
-
- // insert the integrations method
- method.addInstruction(
- listenerInvokeRegister, // insert the integrations instructions right before the listener
- "invoke-static { v$onItemClickViewRegister }, Lapp/revanced/integrations/patches/playback/quality/OldQualityLayoutPatch;->showOldQualityMenu(Landroid/widget/ListView;)V"
- )
-
- return PatchResultSuccess()
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutResourcePatch.kt
deleted file mode 100644
index 965486ce..00000000
--- a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutResourcePatch.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package app.revanced.patches.youtube.video.oldqualitylayout.patch
-
-import app.revanced.patcher.data.ResourceContext
-import app.revanced.patcher.patch.PatchResult
-import app.revanced.patcher.patch.PatchResultError
-import app.revanced.patcher.patch.PatchResultSuccess
-import app.revanced.patcher.patch.ResourcePatch
-import app.revanced.patcher.patch.annotations.DependsOn
-import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
-import app.revanced.patches.shared.settings.preference.impl.StringResource
-import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
-import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
-
-@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
-class OldQualityLayoutResourcePatch : ResourcePatch {
- override fun execute(context: ResourceContext): PatchResult {
- SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
- SwitchPreference(
- "revanced_show_old_video_menu",
- StringResource("revanced_show_old_video_menu_title", "Use old video quality player menu"),
- StringResource("revanced_show_old_video_menu_summary_on", "Old video quality menu is used"),
- StringResource("revanced_show_old_video_menu_summary_off", "Old video quality menu is not used")
- )
- )
-
- videoQualityBottomSheetListFragmentTitle =
- ResourceMappingPatch.resourceMappings.find { it.name == "video_quality_bottom_sheet_list_fragment_title" }
- ?.id ?: return PatchResultError("Could not find resource")
-
- return PatchResultSuccess()
- }
-
- internal companion object {
- var videoQualityBottomSheetListFragmentTitle = -1L
- }
-}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt
index 789e422e..deb0185e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.video.quality.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class RememberVideoQualityCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/NewVideoQualityChangedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/NewVideoQualityChangedFingerprint.kt
new file mode 100644
index 00000000..f1dcf0a5
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/NewVideoQualityChangedFingerprint.kt
@@ -0,0 +1,32 @@
+package app.revanced.patches.youtube.video.quality.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 NewVideoQualityChangedFingerprint : MethodFingerprint(
+ returnType = "L",
+ accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
+ parameters = listOf("L"),
+ opcodes = listOf(
+ Opcode.IGET, // Video resolution (human readable).
+ Opcode.IGET_OBJECT,
+ Opcode.IGET_BOOLEAN,
+ Opcode.IGET_OBJECT,
+ Opcode.INVOKE_STATIC,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.INVOKE_DIRECT,
+ Opcode.IGET_OBJECT,
+ Opcode.INVOKE_INTERFACE,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.GOTO,
+ Opcode.CONST_4,
+ Opcode.IF_NE,
+ Opcode.IGET_OBJECT,
+ Opcode.INVOKE_INTERFACE,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.IGET,
+ )
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt
index d69bb840..a4707a49 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt
@@ -3,6 +3,9 @@ package app.revanced.patches.youtube.video.quality.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
+/**
+ * Resolves with the class found in [VideoQualitySetterFingerprint].
+ */
object SetQualityByIndexMethodClassFieldReferenceFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf("L"),
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt
index 2877f39a..43d32f8f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt
@@ -7,6 +7,7 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
@@ -22,10 +23,12 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
import app.revanced.patches.youtube.video.quality.annotations.RememberVideoQualityCompatibility
+import app.revanced.patches.youtube.video.quality.fingerprints.NewVideoQualityChangedFingerprint
import app.revanced.patches.youtube.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint
import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint
import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySetterFingerprint
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
+import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@Patch
@@ -37,7 +40,8 @@ import org.jf.dexlib2.iface.reference.FieldReference
class RememberVideoQualityPatch : BytecodePatch(
listOf(
VideoQualitySetterFingerprint,
- VideoQualityItemOnClickParentFingerprint
+ VideoQualityItemOnClickParentFingerprint,
+ NewVideoQualityChangedFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
@@ -113,6 +117,7 @@ class RememberVideoQualityPatch : BytecodePatch(
VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted")
+
// Inject a call to set the remembered quality once a video loads.
VideoQualitySetterFingerprint.result?.also {
if (!SetQualityByIndexMethodClassFieldReferenceFingerprint.resolve(context, it.classDef))
@@ -159,6 +164,7 @@ class RememberVideoQualityPatch : BytecodePatch(
)
} ?: return VideoQualitySetterFingerprint.toErrorResult()
+
// Inject a call to remember the selected quality.
VideoQualityItemOnClickParentFingerprint.result?.let {
val onItemClickMethod = it.mutableClass.methods.find { method -> method.name == "onItemClick" }
@@ -172,6 +178,22 @@ class RememberVideoQualityPatch : BytecodePatch(
)
} ?: return PatchResultError("Failed to find onItemClick method")
} ?: return VideoQualityItemOnClickParentFingerprint.toErrorResult()
+
+
+ // Remember video quality if not using old layout menu.
+ NewVideoQualityChangedFingerprint.result?.apply {
+ mutableMethod.apply {
+ val index = scanResult.patternScanResult!!.startIndex
+ val qualityRegister = getInstruction(index).registerA
+
+ addInstruction(
+ index + 1,
+ "invoke-static {v$qualityRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->userChangedQualityInNewFlyout(I)V"
+ )
+ }
+ } ?: return NewVideoQualityChangedFingerprint.toErrorResult()
+
+
return PatchResultSuccess()
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt
index a079bd0f..5c5cfff3 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt
@@ -19,9 +19,7 @@ import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackS
@VideoSpeedCompatibility
@Version("0.0.1")
class VideoSpeed : BytecodePatch() {
-
override fun execute(context: BytecodeContext): PatchResult {
return PatchResultSuccess() // All patches this patch depends on succeed.
}
-
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt
index b97e9293..4072fa4d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.video.speed
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class VideoSpeedCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/GetOldVideoSpeedsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/GetOldVideoSpeedsFingerprint.kt
new file mode 100644
index 00000000..233d1d09
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/GetOldVideoSpeedsFingerprint.kt
@@ -0,0 +1,8 @@
+package app.revanced.patches.youtube.video.speed.custom.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+
+object GetOldVideoSpeedsFingerprint : MethodFingerprint(
+ parameters = listOf("[L", "I"),
+ strings = listOf("menu_item_playback_speed")
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldVideoSpeedMenuFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldVideoSpeedMenuFingerprint.kt
new file mode 100644
index 00000000..3844ab32
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldVideoSpeedMenuFingerprint.kt
@@ -0,0 +1,7 @@
+package app.revanced.patches.youtube.video.speed.custom.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+
+object ShowOldVideoSpeedMenuFingerprint : MethodFingerprint(
+ strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldVideoSpeedMenuIntegrationsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldVideoSpeedMenuIntegrationsFingerprint.kt
new file mode 100644
index 00000000..a672dff9
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldVideoSpeedMenuIntegrationsFingerprint.kt
@@ -0,0 +1,7 @@
+package app.revanced.patches.youtube.video.speed.custom.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+
+object ShowOldVideoSpeedMenuIntegrationsFingerprint : MethodFingerprint(
+ customFingerprint = { method, _ -> method.name == "showOldVideoSpeedMenu" }
+)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt
index 73d02788..b166c819 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt
@@ -1,36 +1,46 @@
package app.revanced.patches.youtube.video.speed.custom.patch
+import app.revanced.extensions.toErrorResult
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.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
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.DependsOn
-import app.revanced.patches.shared.settings.preference.impl.InputType
-import app.revanced.patches.shared.settings.preference.impl.StringResource
-import app.revanced.patches.shared.settings.preference.impl.TextPreference
+import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
+import app.revanced.patches.shared.settings.preference.impl.*
+import app.revanced.patches.youtube.misc.bottomsheet.hook.patch.BottomSheetHookPatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
+import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
-import app.revanced.patches.youtube.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint
-import app.revanced.patches.youtube.video.speed.custom.fingerprints.SpeedLimiterFingerprint
+import app.revanced.patches.youtube.video.speed.custom.fingerprints.*
+import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
+import org.jf.dexlib2.immutable.ImmutableField
@Name("custom-video-speed")
@Description("Adds custom video speed options.")
-@DependsOn([IntegrationsPatch::class])
+@DependsOn([IntegrationsPatch::class, LithoFilterPatch::class, SettingsPatch::class, BottomSheetHookPatch::class])
@Version("0.0.1")
class CustomVideoSpeedPatch : BytecodePatch(
listOf(
- SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint
+ SpeedArrayGeneratorFingerprint,
+ SpeedLimiterFingerprint,
+ GetOldVideoSpeedsFingerprint,
+ ShowOldVideoSpeedMenuIntegrationsFingerprint
)
) {
@@ -45,7 +55,7 @@ class CustomVideoSpeedPatch : BytecodePatch(
inputType = InputType.TEXT_MULTI_LINE,
summary = StringResource(
"revanced_custom_playback_speeds_summary",
- "Add or change the video speeds available"
+ "Add or change the available playback speeds"
)
)
)
@@ -71,7 +81,7 @@ class CustomVideoSpeedPatch : BytecodePatch(
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
- val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->customVideoSpeeds:[F"
+ val videoSpeedsArrayType = "$INTEGRATIONS_CLASS_DESCRIPTOR->customVideoSpeeds:[F"
arrayGenMethod.addInstructions(
arrayLengthConstIndex + 1,
@@ -111,14 +121,72 @@ class CustomVideoSpeedPatch : BytecodePatch(
// edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x
limiterMethod.replaceInstruction(
limiterMinConstIndex,
- "sget v$limiterMinConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->minVideoSpeed:F"
+ "sget v$limiterMinConstDestination, $INTEGRATIONS_CLASS_DESCRIPTOR->minVideoSpeed:F"
)
limiterMethod.replaceInstruction(
limiterMaxConstIndex,
- "sget v$limiterMaxConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->maxVideoSpeed:F"
+ "sget v$limiterMaxConstDestination, $INTEGRATIONS_CLASS_DESCRIPTOR->maxVideoSpeed:F"
)
+ // region Force old video quality menu.
+ // This is necessary, because there is no known way of adding custom video speeds to the new menu.
+
+ BottomSheetHookPatch.addHook(INTEGRATIONS_CLASS_DESCRIPTOR)
+
+ // Required to check if the video speed menu is currently shown.
+ LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
+
+ GetOldVideoSpeedsFingerprint.result?.let { result ->
+ // Add a static INSTANCE field to the class.
+ // This is later used to call "showOldVideoSpeedMenu" on the instance.
+ val instanceField = ImmutableField(
+ result.classDef.type,
+ "INSTANCE",
+ result.classDef.type,
+ AccessFlags.PUBLIC or AccessFlags.STATIC,
+ null,
+ null,
+ null
+ ).toMutable()
+
+ result.mutableClass.staticFields.add(instanceField)
+ // Set the INSTANCE field to the instance of the class.
+ // In order to prevent a conflict with another patch, add the instruction at index 1.
+ result.mutableMethod.addInstruction(1, "sput-object p0, $instanceField")
+
+ // Get the "showOldVideoSpeedMenu" method.
+ // This is later called on the field INSTANCE.
+ val showOldVideoSpeedMenuMethod = ShowOldVideoSpeedMenuFingerprint.also {
+ if (!it.resolve(context, result.classDef))
+ throw ShowOldVideoSpeedMenuFingerprint.toErrorResult()
+ }.result!!.method.toString()
+
+ // Insert the call to the "showOldVideoSpeedMenu" method on the field INSTANCE.
+ ShowOldVideoSpeedMenuIntegrationsFingerprint.result?.mutableMethod?.apply {
+ addInstructionsWithLabels(
+ implementation!!.instructions.lastIndex,
+ """
+ sget-object v0, $instanceField
+ if-nez v0, :not_null
+ return-void
+ :not_null
+ invoke-virtual { v0 }, $showOldVideoSpeedMenuMethod
+ """
+ )
+ } ?: return ShowOldVideoSpeedMenuIntegrationsFingerprint.toErrorResult()
+ } ?: return GetOldVideoSpeedsFingerprint.toErrorResult()
+
+ // endregion
+
return PatchResultSuccess()
}
+ private companion object {
+ private const val FILTER_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/patches/components/VideoSpeedMenuFilterPatch;"
+
+ private const val INTEGRATIONS_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;"
+
+ }
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt
index 660f7d8a..a5fa69c6 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.youtube.video.videoid.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35", "18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class VideoIdCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/annotations/OldVideoQualityMenuCompatibility.kt
similarity index 58%
rename from src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt
rename to src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/annotations/OldVideoQualityMenuCompatibility.kt
index 701f9974..5fe280f9 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/annotations/OldVideoQualityMenuCompatibility.kt
@@ -1,8 +1,8 @@
-package app.revanced.patches.youtube.video.oldqualitylayout.annotations
+package app.revanced.patches.youtube.video.videoqualitymenu.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.20.39", "18.23.35"))])
@Target(AnnotationTarget.CLASS)
-internal annotation class OldQualityLayoutCompatibility
\ No newline at end of file
+internal annotation class OldVideoQualityMenuCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt
similarity index 69%
rename from src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt
rename to src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt
index e671f4c4..4e2424a3 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt
@@ -1,12 +1,12 @@
-package app.revanced.patches.youtube.video.oldqualitylayout.fingerprints
+package app.revanced.patches.youtube.video.videoqualitymenu.fingerprints
import app.revanced.patcher.extensions.or
+import app.revanced.patches.youtube.video.videoqualitymenu.patch.OldVideoQualityMenuResourcePatch
import app.revanced.util.patch.LiteralValueFingerprint
-import app.revanced.patches.youtube.video.oldqualitylayout.patch.OldQualityLayoutResourcePatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
-object QualityMenuViewInflateFingerprint : LiteralValueFingerprint(
+object VideoQualityMenuViewInflateFingerprint : LiteralValueFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L", "L"),
returnType = "L",
@@ -26,5 +26,5 @@ object QualityMenuViewInflateFingerprint : LiteralValueFingerprint(
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST
),
- literal = OldQualityLayoutResourcePatch.videoQualityBottomSheetListFragmentTitle
+ literal = OldVideoQualityMenuResourcePatch.videoQualityBottomSheetListFragmentTitle
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/patch/OldVideoQualityMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/patch/OldVideoQualityMenuPatch.kt
new file mode 100644
index 00000000..b304d1c3
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/patch/OldVideoQualityMenuPatch.kt
@@ -0,0 +1,73 @@
+package app.revanced.patches.youtube.video.videoqualitymenu.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.InstructionExtensions.addInstruction
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patches.youtube.misc.bottomsheet.hook.patch.BottomSheetHookPatch
+import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
+import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
+import app.revanced.patches.youtube.video.videoqualitymenu.annotations.OldVideoQualityMenuCompatibility
+import app.revanced.patches.youtube.video.videoqualitymenu.fingerprints.VideoQualityMenuViewInflateFingerprint
+import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
+
+@Patch
+@DependsOn([
+ IntegrationsPatch::class,
+ OldVideoQualityMenuResourcePatch::class,
+ LithoFilterPatch::class,
+ BottomSheetHookPatch::class
+])
+@Name("old-video-quality-menu")
+@Description("Shows the old video quality with the advanced video quality options instead of the new one.")
+@OldVideoQualityMenuCompatibility
+@Version("0.0.1")
+class OldVideoQualityMenuPatch : BytecodePatch(
+ listOf(VideoQualityMenuViewInflateFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ // region Patch for the old type of the video quality menu.
+
+ VideoQualityMenuViewInflateFingerprint.result?.let {
+ it.mutableMethod.apply {
+ val checkCastIndex = it.scanResult.patternScanResult!!.endIndex
+ val listViewRegister = getInstruction(checkCastIndex).registerA
+
+ addInstruction(
+ checkCastIndex + 1,
+ "invoke-static { v$listViewRegister }, " +
+ "$INTEGRATIONS_CLASS_DESCRIPTOR->" +
+ "showOldVideoQualityMenu(Landroid/widget/ListView;)V"
+ )
+ }
+ }
+
+ // endregion
+
+ // region Patch for the new type of the video quality menu.
+
+ BottomSheetHookPatch.addHook(INTEGRATIONS_CLASS_DESCRIPTOR)
+
+ // Required to check if the video quality menu is currently shown in order to click on the "Advanced" item.
+ LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
+
+ // endregion
+
+ return PatchResultSuccess()
+ }
+
+ private companion object {
+ private const val FILTER_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/patches/components/VideoQualityMenuFilterPatch;"
+
+ private const val INTEGRATIONS_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/patches/playback/quality/OldVideoQualityMenuPatch;"
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/patch/OldVideoQualityMenuResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/patch/OldVideoQualityMenuResourcePatch.kt
new file mode 100644
index 00000000..52365b74
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/patch/OldVideoQualityMenuResourcePatch.kt
@@ -0,0 +1,42 @@
+package app.revanced.patches.youtube.video.videoqualitymenu.patch
+
+import app.revanced.patcher.data.ResourceContext
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultError
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.ResourcePatch
+import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
+import app.revanced.patches.shared.settings.preference.impl.StringResource
+import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
+import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
+
+@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
+class OldVideoQualityMenuResourcePatch : ResourcePatch {
+ override fun execute(context: ResourceContext): PatchResult {
+ SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
+ SwitchPreference(
+ "revanced_show_old_video_quality_menu",
+ StringResource("revanced_show_old_video_quality_menu_title", "Show old video quality menu"),
+ StringResource("revanced_show_old_video_quality_menu_summary_on", "Old video quality menu is shown"),
+ StringResource("revanced_show_old_video_quality_menu_summary_off", "New video quality menu is hidden")
+ )
+ )
+
+ fun findResource(name: String) = ResourceMappingPatch.resourceMappings.find { it.name == name }?.id
+ ?: throw PatchResultError("Could not find resource")
+
+ // Used for the old type of the video quality menu.
+ videoQualityBottomSheetListFragmentTitle = findResource("video_quality_bottom_sheet_list_fragment_title")
+
+ // Used for the new type of the video quality menu.
+ bottomSheetMargins = findResource("bottom_sheet_margins")
+
+ return PatchResultSuccess()
+ }
+
+ internal companion object {
+ var videoQualityBottomSheetListFragmentTitle = -1L
+ var bottomSheetMargins = -1L
+ }
+}
diff --git a/src/main/resources/sponsorblock/host/values/strings.xml b/src/main/resources/sponsorblock/host/values/strings.xml
index d451ce29..7f63c88c 100644
--- a/src/main/resources/sponsorblock/host/values/strings.xml
+++ b/src/main/resources/sponsorblock/host/values/strings.xml
@@ -190,5 +190,4 @@
About
sponsor.ajay.app
Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms
- ReVanced integration by JakubWeg,\nrecoded by oSumAtrIX