diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml
index f36d1d2a1..8b208066e 100644
--- a/.github/workflows/pull_request.yml
+++ b/.github/workflows/pull_request.yml
@@ -26,5 +26,5 @@ jobs:
## Dependencies before merge
- - [] https://github.com/revanced/revanced-integrations
+ - [ ] https://github.com/revanced/revanced-integrations
pr_draft: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ab57c48e..839be08b4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,42 @@
+# [2.169.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.168.0...v2.169.0-dev.1) (2023-04-21)
+
+
+### Bug Fixes
+
+* add missing annotation to patches ([#1882](https://github.com/revanced/revanced-patches/issues/1882)) ([d86b6a4](https://github.com/revanced/revanced-patches/commit/d86b6a4a659172c3f1db8eb883f28dfee4e83e4c))
+* **youtube/hide-video-action-buttons:** change 'Hide create, clip and thanks buttons' to default off ([#1923](https://github.com/revanced/revanced-patches/issues/1923)) ([fc89c86](https://github.com/revanced/revanced-patches/commit/fc89c865f94fffd748809eaf0504cc91f6389500))
+* **youtube/hide-video-action-buttons:** fix 'hide share button' ([#1924](https://github.com/revanced/revanced-patches/issues/1924)) ([bc05e44](https://github.com/revanced/revanced-patches/commit/bc05e4494d914f944a831bfb83a150ad93bb342f))
+* **youtube/microg-support:** remove incorrect patch dependency ([3e0c45c](https://github.com/revanced/revanced-patches/commit/3e0c45c2dff9f6336e42fdd3d1b5b5de5af1b1cb))
+* **youtube/microg-support:** rename patch correctly ([091a25d](https://github.com/revanced/revanced-patches/commit/091a25d46145b1c27791245fca0933e9c8a68e9a))
+* **youtube/return-youtube-dislike:** render dislikes when scrolling into the screen ([#1873](https://github.com/revanced/revanced-patches/issues/1873)) ([85675b8](https://github.com/revanced/revanced-patches/commit/85675b800070de9752b2a4bfea3182381d4cfba4))
+* **youtube/sponsorblock:** do not depend on `remember-playback-speed` patch ([b0834fa](https://github.com/revanced/revanced-patches/commit/b0834faa69755a94f70ae5075a10cf15e8a6b857))
+* **youtube/sponsorblock:** fix autorepeat button layout ([#1868](https://github.com/revanced/revanced-patches/issues/1868)) ([5e148d9](https://github.com/revanced/revanced-patches/commit/5e148d9384e8f9f1bc8f5daa7e68a05574810329))
+* **youtube/spoof-signature-verification:** depend on `client-spoof` patch ([0d47375](https://github.com/revanced/revanced-patches/commit/0d47375092639e3e5dad8d67991004fc2f103606))
+* **youtubevanced/hide-ads:** hide more types of ads ([#1781](https://github.com/revanced/revanced-patches/issues/1781)) ([47ff447](https://github.com/revanced/revanced-patches/commit/47ff447f8ec0e5bbc174f34bd7d61b3031276641))
+* **youtubevanced/hide-ads:** remove broken ad filter ([#1881](https://github.com/revanced/revanced-patches/issues/1881)) ([5b987e1](https://github.com/revanced/revanced-patches/commit/5b987e14e81a47691883a5b5196c7ffee03941d0))
+
+
+### Features
+
+* `change-package-name` patch ([#1864](https://github.com/revanced/revanced-patches/issues/1864)) ([f9a6672](https://github.com/revanced/revanced-patches/commit/f9a6672122eb28fe06c9f5e137906ad868a491d6))
+* `enable-android-debugging` patch ([#1876](https://github.com/revanced/revanced-patches/issues/1876)) ([bd224d9](https://github.com/revanced/revanced-patches/commit/bd224d90deb838ee3e7bd0c16860023ebf113e96))
+* **facebook:** `hide-inbox-ads` patch ([#1893](https://github.com/revanced/revanced-patches/issues/1893)) ([2cfc982](https://github.com/revanced/revanced-patches/commit/2cfc9829e119884ca566d6ad90fd0542317891d7))
+* **id-austria:** bump compatibility to `2.6.0` ([#1827](https://github.com/revanced/revanced-patches/issues/1827)) ([f48e794](https://github.com/revanced/revanced-patches/commit/f48e794eebf9ea44008c4c8a3967ad039d19180a))
+* **inshorts:** `hide-ads` patch ([#1828](https://github.com/revanced/revanced-patches/issues/1828)) ([04a2acc](https://github.com/revanced/revanced-patches/commit/04a2accfe9f9254af9074ad0a309d485cedb01cb))
+* **memegenerator:** `unlock-pro` patch ([#1902](https://github.com/revanced/revanced-patches/issues/1902)) ([7d30541](https://github.com/revanced/revanced-patches/commit/7d3054178187bed294d156d3858613fa63a626ef))
+* **photomath/unlock-plus:** bump compatibility to `8.21.1` ([#1926](https://github.com/revanced/revanced-patches/issues/1926)) ([beb8d9c](https://github.com/revanced/revanced-patches/commit/beb8d9cbf254b4a2b2207a307934be65507dcf80))
+* **photomath:** bump compatibility up to `8.21.0` ([#1886](https://github.com/revanced/revanced-patches/issues/1886)) ([43464fd](https://github.com/revanced/revanced-patches/commit/43464fd6ffe6f097c574156146aeb23f8f026840))
+* **reddit:** bump compatibility to `2023.12.0` ([#1825](https://github.com/revanced/revanced-patches/issues/1825)) ([e3666e6](https://github.com/revanced/revanced-patches/commit/e3666e68ed4816c85fbb110cb098f53fddf135f1))
+* use better patch description ([32fcd25](https://github.com/revanced/revanced-patches/commit/32fcd258c6b00315265c09380550a2e98b5ec9e7))
+* **youtube-music:** `bypass-certificate-checks` patch ([#1810](https://github.com/revanced/revanced-patches/issues/1810)) ([ef8f26f](https://github.com/revanced/revanced-patches/commit/ef8f26fb976c3044039f9bff0496088763ab66cd))
+* **youtube/settings:** disable preferences and add dialog messages to preferences ([#1801](https://github.com/revanced/revanced-patches/issues/1801)) ([05023ba](https://github.com/revanced/revanced-patches/commit/05023bab1d94e04553ac274468bdba7a19ad9180))
+* **youtube/sponsorblock:** skip to video highlight ([#1874](https://github.com/revanced/revanced-patches/issues/1874)) ([83747b7](https://github.com/revanced/revanced-patches/commit/83747b7aea33d8fe4b4b9514fdf7c9081c357410))
+* **youtube:** bump compatibility to `18.08.37` ([29561ec](https://github.com/revanced/revanced-patches/commit/29561eca10e18e11f2d4a7f9bab2f12303490b6f))
+* **youtube:** change default video speed and quality inside the settings menu ([#1880](https://github.com/revanced/revanced-patches/issues/1880)) ([fbb1763](https://github.com/revanced/revanced-patches/commit/fbb17636d8ab9f2a43ead896451804b04464527c))
+* **youtube:** constrain compatibility to `18.08.37` ([7403fc8](https://github.com/revanced/revanced-patches/commit/7403fc86ae7b7d756a2939fa0a507f237aaf6edf))
+* **youtube:** sponsorblock improvements ([#1557](https://github.com/revanced/revanced-patches/issues/1557)) ([b5d712a](https://github.com/revanced/revanced-patches/commit/b5d712a3326d1e8cdb8d8642aa7bd1bee6e30ac1))
+* **youtube:** support version `18.08.37` ([4f4ceab](https://github.com/revanced/revanced-patches/commit/4f4ceab2cc32a38dd3967fd4e81f690330c08f5c))
+
# [2.168.0](https://github.com/revanced/revanced-patches/compare/v2.167.1...v2.168.0) (2023-04-13)
diff --git a/README.md b/README.md
index 12bc437ad..542599e94 100644
--- a/README.md
+++ b/README.md
@@ -9,60 +9,60 @@ The official Patch bundle provided by ReVanced and the community.
| π Patch | π Description | πΉ Target Version |
|:--------:|:--------------:|:-----------------:|
-| `always-autorepeat` | Always repeats the playing video again. | 18.05.40 |
-| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all |
-| `comments` | Hides components related to comments. | 18.05.40 |
-| `copy-video-url` | Adds buttons in player to copy video links. | 18.05.40 |
+| `always-autorepeat` | Always repeats the playing video again. | 18.08.37 |
+| `client-spoof` | Spoofs a patched client to allow playback. | all |
+| `comments` | Hides components related to comments. | 18.08.37 |
+| `copy-video-url` | Adds buttons in player to copy video links. | 18.08.37 |
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
-| `custom-video-buffer` | Lets you change the buffers of videos. | 18.05.40 |
-| `custom-video-speed` | Adds more video speed options. | 18.05.40 |
-| `debugging` | Adds debugging options. | all |
-| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.05.40 |
-| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.05.40 |
-| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.05.40 |
-| `disable-shorts-on-startup` | Disables playing YouTube Shorts when launching YouTube. | 18.05.40 |
+| `custom-video-buffer` | Lets you change the buffers of videos. | 18.08.37 |
+| `custom-video-speed` | Adds more video speed options. | 18.08.37 |
+| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.08.37 |
+| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.08.37 |
+| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.08.37 |
+| `disable-shorts-on-startup` | Disables playing YouTube Shorts when launching YouTube. | 18.08.37 |
| `disable-zoom-haptics` | Disables haptics when zooming. | all |
-| `downloads` | Enables downloading music and videos from YouTube. | 18.05.40 |
-| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.05.40 |
-| `general-ads` | Removes general ads. | 18.05.40 |
-| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.05.40 |
-| `hide-album-cards` | Hides the album cards below the artist description. | 18.05.40 |
-| `hide-artist-card` | Hides the artist card below the searchbar. | 18.05.40 |
-| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.05.40 |
-| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.05.40 |
-| `hide-captions-button` | Hides the captions button on video player. | 18.05.40 |
+| `downloads` | Enables downloading music and videos from YouTube. | 18.08.37 |
+| `enable-debugging` | Adds debugging options. | all |
+| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.08.37 |
+| `general-ads` | Removes general ads. | 18.08.37 |
+| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.08.37 |
+| `hide-album-cards` | Hides the album cards below the artist description. | 18.08.37 |
+| `hide-artist-card` | Hides the artist card below the searchbar. | 18.08.37 |
+| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.08.37 |
+| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.08.37 |
+| `hide-captions-button` | Hides the captions button on video player. | 18.08.37 |
| `hide-cast-button` | Hides the cast button in the video player. | all |
-| `hide-create-button` | Hides the create button in the navigation bar. | 18.05.40 |
-| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.05.40 |
-| `hide-email-address` | Hides the email address in the account switcher. | 18.05.40 |
-| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.05.40 |
-| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.05.40 |
-| `hide-info-cards` | Hides info cards in videos. | 18.05.40 |
-| `hide-my-mix` | Hides mix playlists. | 18.05.40 |
+| `hide-create-button` | Hides the create button in the navigation bar. | 18.08.37 |
+| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.08.37 |
+| `hide-email-address` | Hides the email address in the account switcher. | 18.08.37 |
+| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.08.37 |
+| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.08.37 |
+| `hide-info-cards` | Hides info cards in videos. | 18.08.37 |
+| `hide-my-mix` | Hides mix playlists. | 18.08.37 |
| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | all |
-| `hide-seekbar` | Hides the seekbar. | 18.05.40 |
-| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 18.05.40 |
-| `hide-timestamp` | Hides timestamp in video player. | 18.05.40 |
-| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.05.40 |
-| `hide-watch-in-vr` | Hides the option to watch in VR from the player settings flyout panel. | 18.05.40 |
-| `hide-watermark` | Hides creator's watermarks on videos. | 18.05.40 |
-| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.05.40 |
-| `minimized-playback` | Enables minimized and background playback. | 18.05.40 |
-| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.05.40 |
-| `open-links-externally` | Open links outside of the app directly in your browser. | 18.05.40 |
+| `hide-seekbar` | Hides the seekbar. | 18.08.37 |
+| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 18.08.37 |
+| `hide-timestamp` | Hides timestamp in video player. | 18.08.37 |
+| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.08.37 |
+| `hide-watch-in-vr` | Hides the option to watch in VR from the player settings flyout panel. | 18.08.37 |
+| `hide-watermark` | Hides creator's watermarks on videos. | 18.08.37 |
+| `minimized-playback` | Enables minimized and background playback. | 18.08.37 |
+| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.08.37 |
+| `open-links-externally` | Open links outside of the app directly in your browser. | 18.08.37 |
| `premium-heading` | Shows premium branding on the home screen. | all |
-| `remember-playback-speed` | Adds the ability to remember the playback speed you chose in the video playback speed flyout. | 18.05.40 |
-| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.05.40 |
-| `remove-player-button-background` | Removes the background from the video player buttons. | 18.05.40 |
-| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.05.40 |
-| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.05.40 |
-| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.05.40 |
-| `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.05.40 |
-| `spoof-signature-verification` | Spoofs the client to prevent playback issues. | 18.05.40 |
-| `swipe-controls` | Adds volume and brightness swipe controls. | 18.05.40 |
-| `tablet-mini-player` | Enables the tablet mini player layout. | 18.05.40 |
+| `remember-playback-speed` | Adds the ability to remember the playback speed you chose in the video playback speed flyout. | 18.08.37 |
+| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.08.37 |
+| `remove-player-button-background` | Removes the background from the video player buttons. | 18.08.37 |
+| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.08.37 |
+| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.08.37 |
+| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.08.37 |
+| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.08.37 |
+| `spoof-signature-verification` | Spoofs a patched client to prevent playback issues. | 18.08.37 |
+| `swipe-controls` | Adds volume and brightness swipe controls. | 18.08.37 |
+| `tablet-mini-player` | Enables the tablet mini player layout. | 18.08.37 |
| `theme` | Applies a custom theme. | all |
-| `video-ads` | Removes ads in the video player. | 18.05.40 |
+| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.08.37 |
+| `video-ads` | Removes ads in the video player. | 18.08.37 |
### [π¦ `com.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music)
@@ -71,6 +71,7 @@ The official Patch bundle provided by ReVanced and the community.
| π 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. | 5.39.52 |
| `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 |
@@ -153,8 +154,8 @@ The official Patch bundle provided by ReVanced and the community.
| π Patch | π Description | πΉ Target Version |
|:--------:|:--------------:|:-----------------:|
-| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2023.10.0 |
-| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | 2023.10.0 |
+| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2023.12.0 |
+| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | 2023.12.0 |
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
@@ -163,7 +164,7 @@ The official Patch bundle provided by ReVanced and the community.
| π Patch | π Description | πΉ Target Version |
|:--------:|:--------------:|:-----------------:|
-| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all |
+| `client-spoof` | Spoofs a patched client to allow playback. | all |
| `hide-ads` | Removes general ads. | all |
@@ -181,8 +182,8 @@ The official Patch bundle provided by ReVanced and the community.
| π Patch | π Description | πΉ Target Version |
|:--------:|:--------------:|:-----------------:|
-| `remove-root-detection` | Removes the check for root permissions and unlocked bootloader. | 2.5.2 |
-| `spoof-signature` | Spoofs the signature of the app. | 2.5.2 |
+| `remove-root-detection` | Removes the check for root permissions and unlocked bootloader. | 2.6.0 |
+| `spoof-signature` | Spoofs the signature of the app. | 2.6.0 |
### [π¦ `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit)
@@ -201,6 +202,22 @@ The official Patch bundle provided by ReVanced and the community.
| `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.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca)
+
+
+| π Patch | π Description | πΉ Target Version |
+|:--------:|:--------------:|:-----------------:|
+| `hide-inbox-ads` | Hides ads in inbox. | all |
+
+
### [π¦ `com.instagram.android`](https://play.google.com/store/apps/details?id=com.instagram.android)
@@ -270,7 +287,7 @@ The official Patch bundle provided by ReVanced and the community.
| π Patch | π Description | πΉ Target Version |
|:--------:|:--------------:|:-----------------:|
-| `unlock-plus` | Unlocks plus features. | all |
+| `unlock-plus` | Unlocks plus features. | 8.9.0 |
### [π¦ `io.yuka.android`](https://play.google.com/store/apps/details?id=io.yuka.android)
@@ -321,6 +338,14 @@ The official Patch bundle provided by ReVanced and the community.
| `unlock-pro` | Unlocks all professional features. | 3.4.9 |
+### [π¦ `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
+
+
+| π Patch | π Description | πΉ Target Version |
+|:--------:|:--------------:|:-----------------:|
+| `unlock-pro` | Unlocks pro features. | 4.6364 |
+
+
### [π¦ `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
diff --git a/build.gradle.kts b/build.gradle.kts
index 3d81b8e74..dff3d309d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,5 @@
plugins {
- kotlin("jvm") version "1.7.0"
+ kotlin("jvm") version "1.8.10"
}
group = "app.revanced"
diff --git a/gradle.properties b/gradle.properties
index 07774b7fa..244230232 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,2 @@
kotlin.code.style = official
-version = 2.168.0
+version = 2.169.0-dev.1
diff --git a/patches.json b/patches.json
index 0e6cf82ab..db1e2a2cc 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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"block-embedded-ads","description":"Blocks embedded steam 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":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.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":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"client-spoof","description":"Spoofs the YouTube or Vanced client to prevent playback issues.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]},{"name":"com.vanced.android.youtube","versions":[]}]},{"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":["integrations","comments-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"custom-video-speed","description":"Adds more video speed options.","version":"0.0.1","excluded":false,"options":[{"key":"granularity","title":"Video speed granularity","description":"The granularity of the video speeds. The higher the value, the more speeds will be available.","required":true,"choices":null},{"key":"min","title":"Minimum video speed","description":"The minimum video speed.","required":true,"choices":null},{"key":"max","title":"Maximum video speed","description":"The maximum video speed. Must be greater than the minimum video speed and smaller than 5.","required":true,"choices":null}],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":"debugging","description":"Adds debugging options.","version":"0.0.1","excluded":false,"options":[{"key":"debuggable","title":"App debugging","description":"Whether to make the app debuggable on Android.","required":false,"choices":null}],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","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-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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"disable-capture-restriction","description":"Allows capturing Spotify\u0027s audio output while screen sharing or screen recording.","version":"0.0.2","excluded":false,"options":[],"dependencies":["disable-capture-restriction-resource-patch"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":"Enables downloading music and videos from YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["downloads-resource-patch","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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-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":"enable-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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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":"general-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["GeneralAdsResourcePatch","VerticalScrollPatch","FixBackToExitGesturePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"general-reddit-ads","description":"Removes general ads from the Reddit frontpage and subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":["2021.45.0","2022.43.0","2023.05.0","2023.06.0","2023.07.0","2023.07.1","2023.08.0","2023.09.0","2023.09.1","2023.10.0"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["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-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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"hide-artist-card","description":"Hides the artist card below the searchbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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-create-button","description":"Hides the create button in the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","resource-mapping","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"hide-my-mix","description":"Hides mix playlists.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":[]}]},{"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"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"hide-shorts-button","description":"Hides the shorts button on the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"hide-subreddit-banner","description":"Hides banner ads from comments on subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":["2023.05.0","2023.06.0","2023.07.0","2023.07.1","2023.08.0","2023.09.0","2023.09.1","2023.10.0"]}]},{"name":"hide-timeline-ads","description":"Removes ads from the timeline.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.instagram.android","versions":[]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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-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":["music-microg-resource-patch"],"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":"old-quality-layout","description":"Enables the original video quality flyout in the video player settings","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":"premium-unlock","description":"Unlocks premium functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.citra.citra_emu","versions":[]},{"name":"org.citra.citra_emu.canary","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-playback-speed","description":"Adds the ability to remember the playback speed you chose in the video playback speed flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","video-id-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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-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":["2.2.0"]}]},{"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-player-button-background","description":"Removes the background from the video player buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["2.5.2"]}]},{"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":["2.2.0"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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":[]}]},{"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"sponsorblock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","version":"0.0.1","excluded":false,"options":[],"dependencies":["video-information","player-controls-bytecode-patch","player-type-hook","integrations","sponsorblock-resource-patch","video-id-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["2.5.2"]}]},{"name":"spoof-signature-verification","description":"Spoofs the client to prevent playback issues.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","player-type-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]},{"name":"tasteBuilder-remover","description":"Removes the \"Tell us which artists you like\" card from the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"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},{"key":"darkThemeSeekbarColor","title":"Dark theme seekbar color","description":"The background color of the seekbar of the dark theme. Leave empty for default color.","required":false,"choices":null}],"dependencies":["litho-components-theme"],"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":[]}]},{"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 pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","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 pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","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":"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":"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40"]}]}]
\ 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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"block-embedded-ads","description":"Blocks embedded steam 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":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.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":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.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":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52","5.40.51","5.41.50","5.48.52"]}]},{"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":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]},{"name":"com.vanced.android.youtube","versions":[]}]},{"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":["integrations","comments-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"custom-video-speed","description":"Adds more video speed options.","version":"0.0.1","excluded":false,"options":[{"key":"granularity","title":"Video speed granularity","description":"The granularity of the video speeds. The higher the value, the more speeds will be available.","required":true,"choices":null},{"key":"min","title":"Minimum video speed","description":"The minimum video speed.","required":true,"choices":null},{"key":"max","title":"Maximum video speed","description":"The maximum video speed. Must be greater than the minimum video speed and smaller than 5.","required":true,"choices":null}],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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-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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"disable-capture-restriction","description":"Allows capturing Spotify\u0027s audio output while screen sharing or screen recording.","version":"0.0.2","excluded":false,"options":[],"dependencies":["disable-capture-restriction-resource-patch"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":"Enables downloading music and videos from YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["downloads-resource-patch","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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":false,"options":[{"key":"debuggable","title":"App debugging","description":"Whether to make the app debuggable on Android.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"enable-debugging","description":"Adds debugging options.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings","enable-android-debugging"],"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":"enable-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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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":"general-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["GeneralAdsResourcePatch","VerticalScrollPatch","FixBackToExitGesturePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"general-reddit-ads","description":"Removes general ads from the Reddit frontpage and subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":["2021.45.0","2022.43.0","2023.05.0","2023.06.0","2023.07.0","2023.07.1","2023.08.0","2023.09.0","2023.09.1","2023.10.0","2023.11.0","2023.12.0"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["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 Inshorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.nis.app","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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"hide-artist-card","description":"Hides the artist card below the searchbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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-create-button","description":"Hides the create button in the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","resource-mapping","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"hide-my-mix","description":"Hides mix playlists.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":[]}]},{"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"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"hide-shorts-button","description":"Hides the shorts button on the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"name":"hide-subreddit-banner","description":"Hides banner ads from comments on subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":["2023.05.0","2023.06.0","2023.07.0","2023.07.1","2023.08.0","2023.09.0","2023.09.1","2023.10.0","2023.11.0","2023.12.0"]}]},{"name":"hide-timeline-ads","description":"Removes ads from the timeline.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.instagram.android","versions":[]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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-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":["music-microg-resource-patch"],"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":"old-quality-layout","description":"Enables the original video quality flyout in the video player settings","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":"premium-unlock","description":"Unlocks premium functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.citra.citra_emu","versions":[]},{"name":"org.citra.citra_emu.canary","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-playback-speed","description":"Adds the ability to remember the playback speed you chose in the video playback speed flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","video-id-hook","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.08.37"]}]},{"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","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.08.37"]}]},{"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-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":["2.2.0"]}]},{"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-player-button-background","description":"Removes the background from the video player buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["2.5.2","2.6.0"]}]},{"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":["2.2.0"]}]},{"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.08.37"]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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":[]}]},{"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":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"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.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["2.5.2","2.6.0"]}]},{"name":"spoof-signature-verification","description":"Spoofs a patched client to prevent playback issues.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","player-type-hook","client-spoof"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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.08.37"]}]},{"name":"tasteBuilder-remover","description":"Removes the \"Tell us which artists you like\" card from the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"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},{"key":"darkThemeSeekbarColor","title":"Dark theme seekbar color","description":"The background color of the seekbar of the dark theme. Leave empty for default color.","required":false,"choices":null}],"dependencies":["litho-components-theme"],"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.6.0","8.7.0","8.8.0","8.9.0","8.10.0","8.11.0","8.12.0","8.13.0","8.14.0","8.15.0","8.16.0","8.17.0","8.18.0","8.18.1","8.19.0","8.20.0","8.21.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 pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","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 pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","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 pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureVerificationPatch","LicenseValidationPatch"],"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364"]}]},{"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"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]},{"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":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37"]}]}]
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt b/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt
index 0c6bdeae8..ecdfc0e37 100644
--- a/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt
@@ -4,6 +4,7 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.patch.*
import org.jf.dexlib2.iface.ClassDef
@@ -15,6 +16,7 @@ import java.util.*
@Name("spoof-wifi-connection")
@Description("Spoofs an existing Wi-Fi connection.")
@Version("0.0.1")
+@RequiresIntegrations
internal class SpoofWifiPatch : AbstractTransformInstructionsPatch() {
private companion object {
diff --git a/src/main/kotlin/app/revanced/patches/all/misc/debugging/patch/DebuggingPatc.kt b/src/main/kotlin/app/revanced/patches/all/misc/debugging/patch/DebuggingPatc.kt
new file mode 100644
index 000000000..a5b9942a2
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/all/misc/debugging/patch/DebuggingPatc.kt
@@ -0,0 +1,43 @@
+package app.revanced.patches.all.misc.debugging.patch
+
+import app.revanced.patcher.annotation.Description
+import app.revanced.patcher.annotation.Name
+import app.revanced.patcher.annotation.Version
+import app.revanced.patcher.data.ResourceContext
+import app.revanced.patcher.patch.*
+import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patcher.patch.annotations.Patch
+import org.w3c.dom.Element
+
+@Patch
+@Name("enable-android-debugging")
+@Description("Enables Android debugging capabilities.")
+@Version("0.0.1")
+class EnableAndroidDebuggingPatch : ResourcePatch {
+ override fun execute(context: ResourceContext): PatchResult {
+ if (debuggable == true) {
+ context.xmlEditor["AndroidManifest.xml"].use { dom ->
+ val applicationNode = dom
+ .file
+ .getElementsByTagName("application")
+ .item(0) as Element
+
+ // set application as debuggable
+ applicationNode.setAttribute("android:debuggable", "true")
+ }
+ }
+
+ return PatchResultSuccess()
+ }
+
+ companion object : OptionsContainer() {
+ var debuggable: Boolean? by option(
+ PatchOption.BooleanOption(
+ key = "debuggable",
+ default = true,
+ title = "App debugging",
+ description = "Whether to make the app debuggable on Android.",
+ )
+ )
+ }
+}
diff --git a/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt
new file mode 100644
index 000000000..f94fdf331
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt
@@ -0,0 +1,50 @@
+package app.revanced.patches.all.misc.packagename.patch
+
+import app.revanced.patcher.annotation.Description
+import app.revanced.patcher.annotation.Name
+import app.revanced.patcher.annotation.Version
+import app.revanced.patcher.data.ResourceContext
+import app.revanced.patcher.patch.*
+import app.revanced.patcher.patch.annotations.Patch
+import org.w3c.dom.Element
+
+@Patch(false)
+@Name("change-package-name")
+@Description("Changes the package name.")
+@Version("0.0.1")
+class ChangePackageNamePatch : ResourcePatch {
+ override fun execute(context: ResourceContext): PatchResult {
+ packageName?.let { packageName ->
+ val packageNameRegex = Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")
+ if (!packageName.matches(packageNameRegex))
+ return PatchResultError("Invalid package name")
+
+ var originalPackageName = ""
+ context.xmlEditor["AndroidManifest.xml"].use { editor ->
+ val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
+ originalPackageName = manifest.getAttribute("package")
+ }
+
+ if (!originalPackageName.matches(packageNameRegex))
+ return PatchResultError("Failed to get the original package name")
+
+ context["AndroidManifest.xml"].apply {
+ readText().replace(originalPackageName, packageName).let(::writeText)
+ }
+
+ } ?: return PatchResultError("No package name provided")
+
+ return PatchResultSuccess()
+ }
+
+ companion object : OptionsContainer() {
+ var packageName: String? by option(
+ PatchOption.StringOption(
+ key = "packageName",
+ default = "",
+ title = "Package name",
+ description = "The name of the package to rename of the app.",
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt b/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt
index b9f26c99b..8f4c71a31 100644
--- a/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt
@@ -4,6 +4,7 @@ import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.patch.*
import org.jf.dexlib2.iface.ClassDef
@@ -15,6 +16,7 @@ import java.util.*
@Name("remove-screenshot-restriction")
@Description("Removes the restriction of taking screenshots in apps that normally wouldn't allow it.")
@Version("0.0.1")
+@RequiresIntegrations
internal class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch() {
private companion object {
diff --git a/src/main/kotlin/app/revanced/patches/idaustria/detection/shared/annotations/DetectionCompatibility.kt b/src/main/kotlin/app/revanced/patches/idaustria/detection/shared/annotations/DetectionCompatibility.kt
index bfbb42399..b25a6f409 100644
--- a/src/main/kotlin/app/revanced/patches/idaustria/detection/shared/annotations/DetectionCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/idaustria/detection/shared/annotations/DetectionCompatibility.kt
@@ -3,6 +3,6 @@ package app.revanced.patches.idaustria.detection.shared.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("at.gv.oe.app", arrayOf("2.5.2"))])
+@Compatibility([Package("at.gv.oe.app", arrayOf("2.5.2", "2.6.0"))])
@Target(AnnotationTarget.CLASS)
internal annotation class DetectionCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/inshorts/ad/annotations/HideAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/inshorts/ad/annotations/HideAdsCompatibility.kt
new file mode 100644
index 000000000..372929a12
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/inshorts/ad/annotations/HideAdsCompatibility.kt
@@ -0,0 +1,9 @@
+package app.revanced.patches.inshorts.ad.annotations
+
+import app.revanced.patcher.annotation.Compatibility
+import app.revanced.patcher.annotation.Package
+
+@Compatibility([Package("com.nis.app")])
+
+@Target(AnnotationTarget.CLASS)
+internal annotation class HideAdsCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt
new file mode 100644
index 000000000..1cbb57933
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt
@@ -0,0 +1,9 @@
+package app.revanced.patches.inshorts.ad.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object InshortsAdsFingerprint : MethodFingerprint(
+ "V",
+ strings = listOf("GoogleAdLoader","exception in requestAd")
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/inshorts/ad/patch/InshortsAdsPatch.kt b/src/main/kotlin/app/revanced/patches/inshorts/ad/patch/InshortsAdsPatch.kt
new file mode 100644
index 000000000..7c809f6f8
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/inshorts/ad/patch/InshortsAdsPatch.kt
@@ -0,0 +1,38 @@
+package app.revanced.patches.inshorts.ad.patch
+
+import app.revanced.extensions.toErrorResult
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.annotation.Description
+import app.revanced.patcher.annotation.Name
+import app.revanced.patcher.annotation.Version
+import app.revanced.patcher.extensions.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.Patch
+import app.revanced.patches.inshorts.ad.annotations.HideAdsCompatibility
+import app.revanced.patches.inshorts.ad.fingerprints.InshortsAdsFingerprint
+
+@Patch
+@Name("hide-ads")
+@Description("Removes ads from Inshorts.")
+@HideAdsCompatibility
+@Version("0.0.1")
+class HideAdsPatch : BytecodePatch(
+ listOf(InshortsAdsFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ InshortsAdsFingerprint.result?.let { result ->
+ result.apply {
+ mutableMethod.addInstruction(
+ 0,
+ """
+ return-void
+ """
+ )
+ }
+ } ?: return InshortsAdsFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt b/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt
new file mode 100644
index 000000000..205bca30a
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt
@@ -0,0 +1,24 @@
+package app.revanced.patches.memegenerator.detection.license.fingerprint
+
+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 LicenseValidationFingerprint : MethodFingerprint(
+ returnType = "Z",
+ access = AccessFlags.PUBLIC or AccessFlags.STATIC,
+ parameters = listOf("Landroid/content/Context;"),
+ opcodes = listOf(
+ Opcode.INVOKE_STATIC,
+ Opcode.MOVE_RESULT_WIDE,
+ Opcode.INVOKE_STATIC,
+ Opcode.MOVE_RESULT_WIDE,
+ Opcode.CMP_LONG,
+ Opcode.IF_GEZ,
+ Opcode.CONST_4,
+ Opcode.RETURN,
+ Opcode.CONST_4,
+ Opcode.RETURN
+ )
+)
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/patch/LicenseValidationPatch.kt b/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/patch/LicenseValidationPatch.kt
new file mode 100644
index 000000000..6e514ff70
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/patch/LicenseValidationPatch.kt
@@ -0,0 +1,31 @@
+package app.revanced.patches.memegenerator.detection.license.patch
+
+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.replaceInstructions
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patches.memegenerator.detection.license.fingerprint.LicenseValidationFingerprint
+
+@Description("Disables Firebase license validation.")
+@Version("0.0.1")
+class LicenseValidationPatch : BytecodePatch(
+ listOf(LicenseValidationFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ LicenseValidationFingerprint.result?.apply {
+ mutableMethod.replaceInstructions(
+ 0,
+ """
+ const/4 p0, 0x1
+ return p0
+ """
+ )
+ } ?: throw LicenseValidationFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt b/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt
new file mode 100644
index 000000000..7c0304ebb
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt
@@ -0,0 +1,35 @@
+package app.revanced.patches.memegenerator.detection.signature.fingerprint
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.AccessFlags
+import org.jf.dexlib2.Opcode
+
+@FuzzyPatternScanMethod(2)
+object VerifySignatureFingerprint : MethodFingerprint(
+ returnType = "Z",
+ access = AccessFlags.PUBLIC or AccessFlags.STATIC,
+ parameters = listOf("Landroid/app/Activity;"),
+ opcodes = listOf(
+ Opcode.SGET_OBJECT,
+ Opcode.IF_NEZ,
+ Opcode.INVOKE_STATIC,
+ Opcode.CONST_4,
+ Opcode.CONST_4,
+ Opcode.SGET_OBJECT,
+ Opcode.ARRAY_LENGTH,
+ Opcode.IF_GE,
+ Opcode.AGET_OBJECT,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.SGET_OBJECT,
+ Opcode.IF_EQZ,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.MOVE_RESULT,
+ Opcode.IF_EQZ,
+ Opcode.CONST_4,
+ Opcode.RETURN,
+ Opcode.ADD_INT_LIT8
+ ),
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/patch/SignatureVerificationPatch.kt b/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/patch/SignatureVerificationPatch.kt
new file mode 100644
index 000000000..1b9ca3064
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/patch/SignatureVerificationPatch.kt
@@ -0,0 +1,31 @@
+package app.revanced.patches.memegenerator.detection.signature.patch
+
+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.replaceInstructions
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patches.memegenerator.detection.signature.fingerprint.VerifySignatureFingerprint
+
+@Description("Disables detection of incorrect signature.")
+@Version("0.0.1")
+class SignatureVerificationPatch : BytecodePatch(
+ listOf(VerifySignatureFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ VerifySignatureFingerprint.result?.apply {
+ mutableMethod.replaceInstructions(
+ 0,
+ """
+ const/4 p0, 0x1
+ return p0
+ """
+ )
+ } ?: throw VerifySignatureFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt
new file mode 100644
index 000000000..bf92bccaa
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt
@@ -0,0 +1,8 @@
+package app.revanced.patches.memegenerator.misc.pro.annotations
+
+import app.revanced.patcher.annotation.Compatibility
+import app.revanced.patcher.annotation.Package
+
+@Compatibility([Package("com.zombodroid.MemeGenerator", arrayOf("4.6364"))])
+@Target(AnnotationTarget.CLASS)
+internal annotation class UnlockProCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt
new file mode 100644
index 000000000..be9b266ba
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt
@@ -0,0 +1,22 @@
+package app.revanced.patches.memegenerator.misc.pro.fingerprint
+
+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 IsFreeVersionFingerprint : MethodFingerprint(
+ returnType = "Ljava/lang/Boolean;",
+ access = AccessFlags.PUBLIC or AccessFlags.STATIC,
+ strings = listOf("free"),
+ parameters = listOf("Landroid/content/Context;"),
+ opcodes = listOf(
+ Opcode.SGET,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.CONST_STRING,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.MOVE_RESULT,
+ Opcode.IF_EQZ
+ )
+)
diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/patch/UnlockProVersionPatch.kt b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/patch/UnlockProVersionPatch.kt
new file mode 100644
index 000000000..c0c928e24
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/patch/UnlockProVersionPatch.kt
@@ -0,0 +1,45 @@
+package app.revanced.patches.memegenerator.misc.pro.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.replaceInstructions
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patches.memegenerator.detection.license.patch.LicenseValidationPatch
+import app.revanced.patches.memegenerator.detection.signature.patch.SignatureVerificationPatch
+import app.revanced.patches.memegenerator.misc.pro.annotations.UnlockProCompatibility
+import app.revanced.patches.memegenerator.misc.pro.fingerprint.IsFreeVersionFingerprint
+
+@Patch
+@Name("unlock-pro")
+@Description("Unlocks pro features.")
+@DependsOn([
+ SignatureVerificationPatch::class,
+ LicenseValidationPatch::class
+])
+@UnlockProCompatibility
+@Version("0.0.1")
+class UnlockProVersionPatch : BytecodePatch(
+ listOf(
+ IsFreeVersionFingerprint
+ )
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ IsFreeVersionFingerprint.result?.apply {
+ mutableMethod.replaceInstructions(0,
+ """
+ sget-object p0, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
+ return-object p0
+ """
+ )
+ } ?: throw IsFreeVersionFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt
new file mode 100644
index 000000000..c29b94448
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt
@@ -0,0 +1,18 @@
+package app.revanced.patches.messenger.ads.inbox.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.AccessFlags
+
+object LoadInboxAdsFingerprint : MethodFingerprint(
+ returnType = "V",
+ strings = listOf(
+ "ads_load_begin",
+ "inbox_ads_fetch_start"
+ ),
+ access = AccessFlags.PUBLIC or AccessFlags.STATIC,
+ customFingerprint = {
+ it.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;"
+ }
+)
+
diff --git a/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/patch/HideInboxAdsPatch.kt b/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/patch/HideInboxAdsPatch.kt
new file mode 100644
index 000000000..f18a78d5f
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/patch/HideInboxAdsPatch.kt
@@ -0,0 +1,29 @@
+package app.revanced.patches.messenger.ads.inbox.patch
+
+import app.revanced.extensions.toErrorResult
+import app.revanced.patcher.annotation.*
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.replaceInstruction
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patches.messenger.ads.inbox.fingerprints.LoadInboxAdsFingerprint
+
+@Patch
+@Name("hide-inbox-ads")
+@Description("Hides ads in inbox.")
+@Compatibility([Package("com.facebook.orca")])
+@Version("0.0.1")
+class HideInboxAdsPatch : BytecodePatch(
+ listOf(LoadInboxAdsFingerprint)
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ LoadInboxAdsFingerprint.result?.mutableMethod?.apply {
+ this.replaceInstruction(0, "return-void")
+ } ?: return LoadInboxAdsFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
+
diff --git a/src/main/kotlin/app/revanced/patches/music/misc/androidauto/annotations/BypassCertificateChecksCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/misc/androidauto/annotations/BypassCertificateChecksCompatibility.kt
new file mode 100644
index 000000000..dbbd31992
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/misc/androidauto/annotations/BypassCertificateChecksCompatibility.kt
@@ -0,0 +1,35 @@
+package app.revanced.patches.music.misc.androidauto.annotations
+
+import app.revanced.patcher.annotation.Compatibility
+import app.revanced.patcher.annotation.Package
+
+@Compatibility(
+ [Package(
+ "com.google.android.apps.youtube.music",
+ arrayOf(
+ "5.14.53",
+ "5.16.51",
+ "5.17.51",
+ "5.21.52",
+ "5.22.54",
+ "5.23.50",
+ "5.25.51",
+ "5.25.52",
+ "5.26.52",
+ "5.27.51",
+ "5.28.52",
+ "5.29.52",
+ "5.31.50",
+ "5.34.51",
+ "5.36.51",
+ "5.38.53",
+ "5.39.52",
+ "5.40.51",
+ "5.41.50",
+ "5.48.52"
+ )
+ )]
+)
+@Target(AnnotationTarget.CLASS)
+@Retention(AnnotationRetention.RUNTIME)
+internal annotation class BypassCertificateChecksCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/music/misc/androidauto/fingerprints/CheckCertificateFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/androidauto/fingerprints/CheckCertificateFingerprint.kt
new file mode 100644
index 000000000..f0a261588
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/misc/androidauto/fingerprints/CheckCertificateFingerprint.kt
@@ -0,0 +1,10 @@
+package app.revanced.patches.music.misc.androidauto.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import app.revanced.patches.music.misc.androidauto.patch.BypassCertificateChecksPatch
+
+
+object CheckCertificateFingerprint : MethodFingerprint(
+ "Z",
+ strings = listOf("No match") // Unique in combination with boolean return type
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/music/misc/androidauto/patch/BypassCertificateChecksPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/androidauto/patch/BypassCertificateChecksPatch.kt
new file mode 100644
index 000000000..db5af5baf
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/misc/androidauto/patch/BypassCertificateChecksPatch.kt
@@ -0,0 +1,41 @@
+package app.revanced.patches.music.misc.androidauto.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.addInstruction
+import app.revanced.patcher.extensions.replaceInstruction
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patches.music.misc.androidauto.annotations.BypassCertificateChecksCompatibility
+import app.revanced.patches.music.misc.androidauto.fingerprints.CheckCertificateFingerprint
+
+@Patch
+@Name("bypass-certificate-checks")
+@Description("Bypasses certificate checks which prevent YouTube Music from working on Android Auto.")
+@BypassCertificateChecksCompatibility
+@Version("0.0.1")
+class BypassCertificateChecksPatch : BytecodePatch(
+ listOf(
+ CheckCertificateFingerprint
+ )
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ CheckCertificateFingerprint.result?.let { result ->
+ val noMatchIndex = result.scanResult.stringsScanResult!!.matches.first().index
+
+ result.mutableMethod.apply {
+ val isPartnerIndex = noMatchIndex + 2
+
+ replaceInstruction(isPartnerIndex, "const/4 p1, 0x1")
+ addInstruction(isPartnerIndex + 1, "return p1")
+ }
+ } ?: return CheckCertificateFingerprint.toErrorResult()
+
+ return PatchResultSuccess()
+ }
+}
diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/annotations/DisableSignatureDetectionCompatibility.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/annotations/DisableSignatureDetectionCompatibility.kt
deleted file mode 100644
index 38ecde594..000000000
--- a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/annotations/DisableSignatureDetectionCompatibility.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.photomath.detection.signature.annotations
-
-import app.revanced.patcher.annotation.Compatibility
-import app.revanced.patcher.annotation.Package
-
-@Compatibility([Package("com.microblink.photomath")])
-@Target(AnnotationTarget.CLASS)
-internal annotation class DisableSignatureDetectionCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt
index 26fb72655..2f460c694 100644
--- a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt
@@ -1,9 +1,18 @@
package app.revanced.patches.photomath.detection.signature.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 CheckSignatureFingerprint : MethodFingerprint(
+ returnType = "V",
+ access = AccessFlags.PUBLIC or AccessFlags.FINAL,
+ customFingerprint = {
+ (it.definingClass == "Lcom/microblink/photomath/main/activity/LauncherActivity;" ||
+ it.definingClass == "Lcom/microblink/photomath/PhotoMath;") &&
+ it.name == "onCreate"
+ },
strings = listOf(
"currentSignature"
),
@@ -18,4 +27,4 @@ object CheckSignatureFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
)
-)
\ No newline at end of file
+)
diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/MainOnCreateFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/MainOnCreateFingerprint.kt
deleted file mode 100644
index f263f0b73..000000000
--- a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/MainOnCreateFingerprint.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package app.revanced.patches.photomath.detection.signature.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.AccessFlags
-
-object MainOnCreateFingerprint : MethodFingerprint(
- returnType = "V",
- access = AccessFlags.PUBLIC or AccessFlags.FINAL,
- customFingerprint = { methodDef ->
- methodDef.definingClass == "Lcom/microblink/photomath/PhotoMath;" && methodDef.name == "onCreate"
- }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/patch/SignatureDetectionPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/patch/SignatureDetectionPatch.kt
index f8a07bd9e..d8c5beaae 100644
--- a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/patch/SignatureDetectionPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/patch/SignatureDetectionPatch.kt
@@ -1,42 +1,33 @@
package app.revanced.patches.photomath.detection.signature.patch
+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.instruction
import app.revanced.patcher.extensions.replaceInstruction
-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.patches.photomath.detection.signature.annotations.DisableSignatureDetectionCompatibility
import app.revanced.patches.photomath.detection.signature.fingerprints.CheckSignatureFingerprint
-import app.revanced.patches.photomath.detection.signature.fingerprints.MainOnCreateFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Description("Disables detection of incorrect signature.")
-@DisableSignatureDetectionCompatibility
-@Version("0.0.1")
+@Version("0.0.2")
class SignatureDetectionPatch : BytecodePatch(
listOf(
- MainOnCreateFingerprint
+ CheckSignatureFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
- val mainOnCreate = MainOnCreateFingerprint.result!!
-
- val patternResult = CheckSignatureFingerprint.also {
- it.resolve(context, mainOnCreate.method, mainOnCreate.classDef)
- }.result!!.scanResult.patternScanResult!!
-
- mainOnCreate.mutableMethod.apply {
- val signatureCheckInstruction = instruction(patternResult.endIndex)
+ CheckSignatureFingerprint.result?.apply {
+ val signatureCheckInstruction = mutableMethod.instruction(scanResult.patternScanResult!!.endIndex)
val checkRegister = (signatureCheckInstruction as OneRegisterInstruction).registerA
- replaceInstruction(signatureCheckInstruction.location.index, "const/4 v$checkRegister, 0x1")
- }
+ mutableMethod.replaceInstruction(signatureCheckInstruction.location.index, "const/4 v$checkRegister, 0x1")
+ } ?: throw CheckSignatureFingerprint.toErrorResult()
return PatchResultSuccess()
}
-}
\ No newline at end of file
+}
diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt
index e8d50c365..29f8379df 100644
--- a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt
+++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt
@@ -3,6 +3,28 @@ package app.revanced.patches.photomath.misc.unlockplus.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
-@Compatibility([Package("com.microblink.photomath")])
+@Compatibility(
+ [Package(
+ "com.microblink.photomath", arrayOf(
+ "8.6.0",
+ "8.7.0",
+ "8.8.0",
+ "8.9.0",
+ "8.10.0",
+ "8.11.0",
+ "8.12.0",
+ "8.13.0",
+ "8.14.0",
+ "8.15.0",
+ "8.16.0",
+ "8.17.0",
+ "8.18.0",
+ "8.18.1",
+ "8.19.0",
+ "8.20.0",
+ "8.21.0",
+ )
+ )]
+)
@Target(AnnotationTarget.CLASS)
-internal annotation class UnlockPlusCompatibilty
\ No newline at end of file
+internal annotation class UnlockPlusCompatibilty
diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt
index c1043935e..ffac6ed55 100644
--- a/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt
@@ -13,7 +13,9 @@ import app.revanced.patcher.annotation.Package
"2023.08.0",
"2023.09.0",
"2023.09.1",
- "2023.10.0"
+ "2023.10.0",
+ "2023.11.0",
+ "2023.12.0"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt
index 7703e68d2..e513e941e 100644
--- a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt
@@ -15,7 +15,9 @@ import app.revanced.patcher.annotation.Package
"2023.08.0",
"2023.09.0",
"2023.09.1",
- "2023.10.0"
+ "2023.10.0",
+ "2023.11.0",
+ "2023.12.0"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt
index c58e71c93..49c91185d 100644
--- a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt
@@ -1,5 +1,6 @@
package app.revanced.patches.shared.misc.fix.spoof.patch
+import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -16,22 +17,26 @@ import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch
@Name("client-spoof")
-@Description("Spoofs the YouTube or Vanced client to prevent playback issues.")
+@Description("Spoofs a patched client to allow playback.")
@ClientSpoofCompatibility
@Version("0.0.1")
class ClientSpoofPatch : BytecodePatch(
listOf(UserAgentHeaderBuilderFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
- val result = UserAgentHeaderBuilderFingerprint.result!!
- val method = result.mutableMethod
+ UserAgentHeaderBuilderFingerprint.result?.let { result ->
+ val insertIndex = result.scanResult.patternScanResult!!.endIndex
+ result.mutableMethod.apply {
+ val packageNameRegister = (instruction(insertIndex) as FiveRegisterInstruction).registerD
+ addInstruction(insertIndex, "const-string v$packageNameRegister, \"$ORIGINAL_PACKAGE_NAME\"")
+ }
- val insertIndex = result.scanResult.patternScanResult!!.endIndex
- val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD
-
- val originalPackageName = "com.google.android.youtube"
- method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"")
+ } ?: return UserAgentHeaderBuilderFingerprint.toErrorResult()
return PatchResultSuccess()
}
+
+ private companion object {
+ private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube"
+ }
}
diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt
index 608dccca4..90795e1f7 100644
--- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt
@@ -11,6 +11,7 @@ import org.w3c.dom.Element
* @param name The name of the array resource.
* @param items The items of the array resource.
*/
+// TODO: allow specifying an array resource file instead of using a list of StringResources
internal data class ArrayResource(
override val name: String,
val items: List
diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt
index 78d9f1d38..2845849bc 100644
--- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt
@@ -1,10 +1,7 @@
package app.revanced.patches.shared.settings.preference.impl
-import app.revanced.patches.shared.settings.preference.BasePreference
-import app.revanced.patches.shared.settings.preference.IResource
-import app.revanced.patches.shared.settings.preference.addDefault
-import app.revanced.patches.shared.settings.preference.addSummary
-import app.revanced.patches.shared.settings.preference.SummaryType
+import app.revanced.patches.shared.settings.preference.*
+import app.revanced.patches.shared.settings.resource.patch.AbstractSettingsResourcePatch.Companion.include
import org.w3c.dom.Document
import org.w3c.dom.Element
@@ -16,16 +13,21 @@ import org.w3c.dom.Element
* @param default The default value of the switch.
* @param summaryOn The summary to show when the preference is enabled.
* @param summaryOff The summary to show when the preference is disabled.
+ * @param userDialogMessage The message to show in a dialog when the user toggles the preference.
*/
internal class SwitchPreference(
key: String, title: StringResource,
val default: Boolean = false,
val summaryOn: StringResource? = null,
- val summaryOff: StringResource? = null
+ val summaryOff: StringResource? = null,
+ val userDialogMessage: StringResource? = null
) : BasePreference(key, title) {
override val tag: String = "SwitchPreference"
override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element {
+ // dialog message is stored as a regular string and later referenced by SettingsEnum
+ userDialogMessage?.include()
+
return super.serialize(ownerDocument, resourceCallback).apply {
addDefault(default)
addSummary(summaryOn?.also { resourceCallback?.invoke(it) }, SummaryType.ON)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt
index 876c3ebab..3560b8147 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 bf9f741de..163353849 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 48e04f2d3..313c2f2b8 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt
index 44dfc0d18..15f5b8419 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 caa5ea370..b9f287107 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 15b2e8d27..b217cbbed 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 f4de5e41e..3d2010909 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 81c954045..1abfd93ab 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt
index 1fcb40917..6d6f9ef36 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt
@@ -31,18 +31,11 @@ class HideButtonsPatch : ResourcePatch {
StringResource("revanced_hide_buttons_title", "Hide action buttons"),
listOf(
SwitchPreference(
- "revanced_hide_like_button",
- StringResource("revanced_hide_like_button_title", "Hide like button"),
+ "revanced_hide_like_dislike_button",
+ StringResource("revanced_hide_like_dislike_button_title", "Hide like and dislike buttons"),
false,
- StringResource("revanced_hide_like_button_summary_on", "Like button is hidden"),
- StringResource("revanced_hide_like_button_summary_off", "Like button is shown")
- ),
- SwitchPreference(
- "revanced_hide_dislike_button",
- StringResource("revanced_hide_dislike_button_title", "Hide dislike button"),
- false,
- StringResource("revanced_hide_dislike_button_summary_on", "Dislike button is hidden"),
- StringResource("revanced_hide_dislike_button_summary_off", "Dislike button is shown")
+ StringResource("revanced_hide_like_dislike_button_summary_on", "Like and dislike buttons are hidden"),
+ StringResource("revanced_hide_like_dislike_button_summary_off", "Like and dislike buttons are shown")
),
SwitchPreference(
"revanced_hide_download_button",
@@ -59,18 +52,11 @@ class HideButtonsPatch : ResourcePatch {
StringResource("revanced_hide_playlist_button_summary_off", "Playlist button is shown")
),
SwitchPreference(
- "revanced_hide_action_button",
- StringResource("revanced_hide_action_button_title", "Hide create, clip and thanks buttons"),
- true,
- StringResource("revanced_hide_action_button_summary_on", "Buttons are hidden"),
- StringResource("revanced_hide_action_button_summary_off", "Buttons are shown")
- ),
- SwitchPreference(
- "revanced_hide_share_button",
- StringResource("revanced_hide_share_button_title", "Hide share button"),
+ "revanced_hide_action_buttons",
+ StringResource("revanced_hide_action_buttons_title", "Hide all other action buttons"),
false,
- StringResource("revanced_hide_share_button_summary_on", "Share button is hidden"),
- StringResource("revanced_hide_share_button_summaryoff", "Share button is shown")
+ StringResource("revanced_hide_action_buttons_summary_on", "Share, remix, clip, thanks, shop, live chat buttons are hidden"),
+ StringResource("revanced_hide_action_buttons_summary_off", "Share, remix, clip, thanks, shop, live chat buttons are shown")
)
),
StringResource("revanced_hide_buttons_summary", "Hide or show buttons under videos")
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 2e5c24c4a..5ec82ebce 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt
index cdc013341..2700bbad9 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt
@@ -6,6 +6,7 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
+import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
@@ -20,6 +21,7 @@ import app.revanced.patches.youtube.layout.buttons.autoplay.fingerprints.LayoutC
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
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.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@@ -66,12 +68,15 @@ class HideAutoplayButtonPatch : BytecodePatch(
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction
+ // can be clobbered because this register is overwritten after the injected code
+ val clobberRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA
+
addInstructions(
insertIndex,
"""
invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z
- move-result v11
- if-eqz v11, :hidden
+ move-result v$clobberRegister
+ if-eqz v$clobberRegister, :hidden
""", listOf(ExternalLabel("hidden", jumpInstruction))
)
} ?: return LayoutConstructorFingerprint.toErrorResult()
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 6400c43f3..7bce79a2a 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/pivotbar/shared/annotations/PivotBarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/pivotbar/shared/annotations/PivotBarCompatibility.kt
index 6a1a5c71b..64b22133a 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/pivotbar/shared/annotations/PivotBarCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/pivotbar/shared/annotations/PivotBarCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt
index 810381462..b3d8a4a5d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt
@@ -5,14 +5,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 7cc609fe9..d69330041 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt
index 26c4f318e..0d0799a5f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 83790642a..4bd60942d 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt
index d2dfdcaa2..7fa3e0f76 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 a44f34ffc..f61f1f2b3 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt
index ef7a8b81b..0ad96367d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt
@@ -7,12 +7,9 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
object CrowdfundingBoxFingerprint : MethodFingerprint(
opcodes = listOf(
- Opcode.CONST_4,
- Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IPUT_OBJECT,
- Opcode.CONST,
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction ->
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt
index 82435026f..94d3b103f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt
@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.crowdfundingbox.bytecode.patch
+import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -15,7 +16,7 @@ import app.revanced.patches.youtube.layout.hide.crowdfundingbox.annotations.Crow
import app.revanced.patches.youtube.layout.hide.crowdfundingbox.bytecode.fingerprints.CrowdfundingBoxFingerprint
import app.revanced.patches.youtube.layout.hide.crowdfundingbox.resource.patch.CrowdfundingBoxResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
-import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
+import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch
@DependsOn([IntegrationsPatch::class, CrowdfundingBoxResourcePatch::class])
@@ -29,18 +30,20 @@ class CrowdfundingBoxPatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
- val crowdfundingBoxResult = CrowdfundingBoxFingerprint.result!!
- val crowdfundingBoxMethod = crowdfundingBoxResult.mutableMethod
+ CrowdfundingBoxFingerprint.result?.let {
+ it.mutableMethod.apply {
+ val insertIndex = it.scanResult.patternScanResult!!.endIndex
+ val objectRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA
- val moveResultObjectIndex =
- crowdfundingBoxResult.scanResult.patternScanResult!!.endIndex - 2
-
- crowdfundingBoxMethod.addInstruction(
- moveResultObjectIndex + 1, """
- invoke-static {v${(crowdfundingBoxMethod.instruction(moveResultObjectIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideCrowdfundingBoxPatch;->hideCrowdfundingBox(Landroid/view/View;)V
- """
- )
+ addInstruction(insertIndex, "invoke-static {v$objectRegister}, $INTEGRATIONS_METHOD_DESCRIPTOR")
+ }
+ } ?: return CrowdfundingBoxFingerprint.toErrorResult()
return PatchResultSuccess()
}
+
+ private companion object {
+ const val INTEGRATIONS_METHOD_DESCRIPTOR =
+ "Lapp/revanced/integrations/patches/HideCrowdfundingBoxPatch;->hideCrowdfundingBox(Landroid/view/View;)V"
+ }
}
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 4da83d894..397822fdd 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 e82d9cf54..2cb65f028 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
@@ -13,7 +13,8 @@ import app.revanced.patcher.annotation.Package
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 20e95b8d5..931a8cbe8 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/mixplaylists/annotations/MixPlaylistsPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/mixplaylists/annotations/MixPlaylistsPatchCompatibility.kt
index b3262fdb3..08237e9cf 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/mixplaylists/annotations/MixPlaylistsPatchCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/mixplaylists/annotations/MixPlaylistsPatchCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 0736123e4..a4f0ce845 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 7d3f9ef97..1fd33ec99 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
@@ -13,7 +13,8 @@ import app.revanced.patcher.annotation.Package
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 6b14849b1..6646bb1aa 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 e181a7231..57439d1de 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
@@ -13,7 +13,8 @@ import app.revanced.patcher.annotation.Package
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt
index 0e29cb5a7..1e2cb301e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/annotations/HideTimeAndSeekbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/annotations/HideTimeAndSeekbarCompatibility.kt
deleted file mode 100644
index 9e9afee29..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/annotations/HideTimeAndSeekbarCompatibility.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package app.revanced.patches.youtube.layout.hidetimeandseekbar.annotations
-
-import app.revanced.patcher.annotation.Compatibility
-import app.revanced.patcher.annotation.Package
-
-@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
-)
-@Target(AnnotationTarget.CLASS)
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class HideTimeAndSeekbarCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt
index 79cb458eb..446c1750e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 8d4ada3b0..43472021d 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 3596c6cf1..b83c3003d 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 c84dbac0d..d3f7bd41c 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,19 +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(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
-)
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.08.37"))])
@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/DislikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikeFingerprint.kt
index 81c56995c..63609aff7 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikeFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikeFingerprint.kt
@@ -1,11 +1,8 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
-import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.AccessFlags
object DislikeFingerprint : MethodFingerprint(
"V",
- AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
strings = listOf("like/dislike")
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt
index f3d9a8f04..5761a395e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt
@@ -1,14 +1,11 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
-import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.AccessFlags
@FuzzyPatternScanMethod(2)
object LikeFingerprint : MethodFingerprint(
"V",
- AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
strings = listOf("like/like")
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt
index 17b43b252..9c226ccf8 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt
@@ -1,11 +1,8 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
-import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.AccessFlags
object RemoveLikeFingerprint : MethodFingerprint(
"V",
- AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
strings = listOf("like/removelike")
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt
index 7179eb3ac..27e529824 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt
@@ -10,11 +10,12 @@ object ShortsTextComponentParentFingerprint : MethodFingerprint(
access = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L", "L"),
opcodes = listOf(
- Opcode.IF_EQZ,
- Opcode.CONST_4,
- Opcode.IF_EQ,
- Opcode.CONST_4,
- Opcode.IF_EQ,
+ Opcode.INVOKE_STATIC,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.GOTO,
+ Opcode.INVOKE_STATIC,
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
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
new file mode 100644
index 000000000..c555cb827
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt
@@ -0,0 +1,34 @@
+package app.revanced.patches.youtube.layout.returnyoutubedislike.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
+
+/**
+ * Resolves against the same method that [TextComponentContextFingerprint] resolves to.
+ */
+object TextComponentAtomicReferenceFingerprint : MethodFingerprint(
+ returnType = "L",
+ access = AccessFlags.PROTECTED or AccessFlags.FINAL,
+ parameters = listOf("L"),
+ opcodes = listOf(
+ Opcode.MOVE_OBJECT, // available unused register
+ Opcode.MOVE_OBJECT_FROM16,
+ Opcode.MOVE_OBJECT_FROM16,
+ Opcode.MOVE_FROM16,
+ Opcode.INVOKE_VIRTUAL, // CharSequence atomic reference
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.CHECK_CAST,
+ Opcode.MOVE_OBJECT, // CharSequence reference, and control flow label. Insert code here.
+ Opcode.INVOKE_VIRTUAL_RANGE,
+ Opcode.MOVE_RESULT,
+ Opcode.IF_EQZ,
+ Opcode.INVOKE_VIRTUAL_RANGE,
+ 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/TextComponentConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt
new file mode 100644
index 000000000..ca29b8eee
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt
@@ -0,0 +1,11 @@
+package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
+
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.AccessFlags
+
+object TextComponentConstructorFingerprint : MethodFingerprint(
+ access = AccessFlags.CONSTRUCTOR or AccessFlags.PRIVATE,
+ strings = listOf("TextComponent")
+)
\ 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
new file mode 100644
index 000000000..1a23e7046
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt
@@ -0,0 +1,24 @@
+package app.revanced.patches.youtube.layout.returnyoutubedislike.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
+
+/**
+ * Resolves against the same method that [TextComponentContextFingerprint] resolves to.
+ */
+object TextComponentContextFingerprint : MethodFingerprint(
+ returnType = "L",
+ access = AccessFlags.PROTECTED or AccessFlags.FINAL,
+ parameters = listOf("L"),
+ opcodes = listOf(
+ Opcode.IGET_OBJECT, // conversion context field name
+ Opcode.IGET_OBJECT,
+ Opcode.IGET_OBJECT,
+ Opcode.IGET_BOOLEAN,
+ Opcode.IGET,
+ Opcode.IGET,
+ Opcode.IGET,
+ )
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentFingerprint.kt
deleted file mode 100644
index dadd8e607..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentFingerprint.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
-
-
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-
-object TextComponentFingerprint : MethodFingerprint(
- strings = listOf("com.google.android.apps.youtube.music")
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentSpecParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentSpecParentFingerprint.kt
deleted file mode 100644
index 631ca5f77..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentSpecParentFingerprint.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
-
-
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-
-object TextComponentSpecParentFingerprint : MethodFingerprint(
- strings = listOf("TextComponentSpec: No converter for extension: ")
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt
index 6a63c83d0..3796ee62b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt
@@ -9,6 +9,7 @@ import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
+import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
@@ -26,6 +27,8 @@ import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
+import org.jf.dexlib2.iface.instruction.ReferenceInstruction
+import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch
@DependsOn(
@@ -42,7 +45,7 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Version("0.0.1")
class ReturnYouTubeDislikePatch : BytecodePatch(
listOf(
- TextComponentSpecParentFingerprint,
+ TextComponentConstructorFingerprint,
ShortsTextComponentParentFingerprint,
LikeFingerprint,
DislikeFingerprint,
@@ -50,13 +53,13 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
- // region Inject newVideoLoaded event handler
+ // region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
VideoIdPatch.injectCall("$INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
// endregion
- // region Hook interaction
+ // region Hook like/dislike/remove like button clicks to send votes to the API.
listOf(
LikeFingerprint.toPatch(Vote.LIKE),
@@ -76,29 +79,56 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
// endregion
- // region Hook components
+ // region Hook creation of Spans and the cached lookup of them.
- TextComponentFingerprint.also { it.resolve(context, TextComponentSpecParentFingerprint.result!!.classDef) }
- .result?.let {
- with(it.mutableMethod) {
- val createComponentMethod = this
+ // Alternatively the hook can be made at the creation of Spans in TextComponentSpec,
+ // And it works in all situations except it fails to update the Span when the user dislikes,
+ // since the underlying (likes only) text did not change.
+ // This hook handles all situations, as it's where the created Spans are stored and later reused.
+ TextComponentContextFingerprint.also {
+ it.resolve(
+ context,
+ TextComponentConstructorFingerprint.result!!.classDef
+ )
+ }.result?.also { result ->
+ if (!TextComponentAtomicReferenceFingerprint.resolve(context, result.method, result.classDef))
+ throw TextComponentAtomicReferenceFingerprint.toErrorResult()
+ }?.let { textComponentContextFingerprintResult ->
+ val conversionContextIndex = textComponentContextFingerprintResult
+ .scanResult.patternScanResult!!.startIndex
+ val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!!
+ .scanResult.patternScanResult!!.startIndex
- val conversionContextParam = 5
- val textRefParam = createComponentMethod.parameters.size - 2
- // Insert index must be 0, otherwise UI does not updated correctly in some situations
- // such as switching from full screen or when using previous/next overlay buttons.
- val insertIndex = 0
+ textComponentContextFingerprintResult.mutableMethod.apply {
+ // Get the conversion context obfuscated field name, and the registers for the AtomicReference and CharSequence
+ val conversionContextFieldName =
+ (instruction(conversionContextIndex) as ReferenceInstruction).reference.toString()
+ val contextRegister = // any free register
+ (instruction(atomicReferenceStartIndex) as TwoRegisterInstruction).registerB
+ val atomicReferenceRegister =
+ (instruction(atomicReferenceStartIndex + 4) as BuilderInstruction35c).registerC
- createComponentMethod.addInstructions(
- insertIndex,
- """
- move-object/from16 v7, p$conversionContextParam
- move-object/from16 v8, p$textRefParam
- invoke-static {v7, v8}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->onComponentCreated(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;)V
- """
- )
- }
- } ?: return TextComponentFingerprint.toErrorResult()
+ val insertIndex = atomicReferenceStartIndex + 7
+ val moveCharSequenceInstruction = instruction(insertIndex) as TwoRegisterInstruction
+ val charSequenceRegister = moveCharSequenceInstruction.registerB
+
+ // Insert as first instructions at the control flow label.
+ // Must replace the existing instruction to preserve the label, and then insert the remaining instructions.
+ replaceInstruction(insertIndex, "move-object/from16 v$contextRegister, p0")
+ addInstructions(
+ insertIndex + 1, """
+ iget-object v$contextRegister, v$contextRegister, $conversionContextFieldName # copy obfuscated context field into free register
+ invoke-static {v$contextRegister, v$atomicReferenceRegister, v$charSequenceRegister}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
+ move-result-object v$charSequenceRegister
+ move-object v${moveCharSequenceInstruction.registerA}, v${moveCharSequenceInstruction.registerB} # original instruction at the insertion point
+ """
+ )
+ }
+ } ?: return TextComponentContextFingerprint.toErrorResult()
+
+ // endregion
+
+ // region Hook for Short videos.
ShortsTextComponentParentFingerprint.result?.let {
context
@@ -111,22 +141,23 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
return PatchResultError("Method signature did not match: $this $parameterTypes")
val insertIndex = implementation!!.instructions.size - 1
-
val spannedParameterRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA
val parameter = (instruction(insertIndex - 2) as BuilderInstruction35c).reference
if (!parameter.toString().endsWith("Landroid/text/Spanned;"))
return PatchResultError("Method signature parameter did not match: $parameter")
- addInstructions(
- insertIndex,
- """
- invoke-static {v$spannedParameterRegister}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->onShortsComponentCreated(Landroid/text/Spanned;)Landroid/text/Spanned;
- move-result-object v$spannedParameterRegister
- """
- )
+ insertShorts(insertIndex, spannedParameterRegister)
}
}
+
+ // Additional hook, called after user dislikes.
+ with(it.mutableMethod) {
+ val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2
+ val overwriteRegister = (implementation!!.instructions.elementAt(insertIndex - 1)
+ as OneRegisterInstruction).registerA
+ insertShorts(insertIndex, overwriteRegister)
+ }
} ?: return ShortsTextComponentParentFingerprint.toErrorResult()
// endregion
@@ -139,13 +170,20 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
"Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;"
private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind)
- }
+ private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote)
+ private enum class Vote(val value: Int) {
+ LIKE(1),
+ DISLIKE(-1),
+ REMOVE_LIKE(0)
+ }
- private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote)
-
- private enum class Vote(val value: Int) {
- LIKE(1),
- DISLIKE(-1),
- REMOVE_LIKE(0)
+ private fun MutableMethod.insertShorts(index: Int, register: Int) {
+ addInstructions(
+ index, """
+ invoke-static {v$register}, $INTEGRATIONS_PATCH_CLASS_DESCRIPTOR->onShortsComponentCreated(Landroid/text/Spanned;)Landroid/text/Spanned;
+ move-result-object v$register
+ """
+ )
+ }
}
}
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 9851eb560..91f712441 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
@@ -13,7 +13,8 @@ import app.revanced.patcher.annotation.Package
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 481d696cb..c60f83030 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
@@ -4,18 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
+ [Package("com.google.android.youtube", arrayOf("18.08.37"))]
)
@Target(AnnotationTarget.CLASS)
internal annotation class SponsorBlockCompatibility
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt
deleted file mode 100644
index d17333720..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints
-
-
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.util.MethodUtil
-
-object NextGenWatchLayoutFingerprint : MethodFingerprint(
- "V", // constructors return void, in favour of speed of matching, this fingerprint has been added
- customFingerprint = { methodDef -> MethodUtil.isConstructor(methodDef) && methodDef.parameterTypes.size == 3 && methodDef.definingClass.endsWith("NextGenWatchLayout;") }
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt
index b7e775ca2..a73fc2060 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt
@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.sponsorblock.bytecode.patch
+import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -22,6 +23,8 @@ import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility
import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.*
import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch
+import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatFingerprint
+import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParentFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
@@ -37,12 +40,14 @@ import org.jf.dexlib2.iface.reference.StringReference
@Patch
@DependsOn(
dependencies = [
- VideoInformationPatch::class, // updates video information and adds method to seek in video
- PlayerControlsBytecodePatch::class,
- PlayerTypeHookPatch::class,
IntegrationsPatch::class,
+ VideoIdPatch::class,
+ // Required to skip segments on time.
+ VideoInformationPatch::class,
+ // Used to prevent SponsorBlock from running on Shorts because SponsorBlock does not yet support Shorts.
+ PlayerTypeHookPatch::class,
+ PlayerControlsBytecodePatch::class,
SponsorBlockResourcePatch::class,
- VideoIdPatch::class
]
)
@Name("sponsorblock")
@@ -52,39 +57,41 @@ import org.jf.dexlib2.iface.reference.StringReference
class SponsorBlockBytecodePatch : BytecodePatch(
listOf(
SeekbarFingerprint,
- NextGenWatchLayoutFingerprint,
AppendTimeFingerprint,
PlayerOverlaysLayoutInitFingerprint,
+ AutoRepeatParentFingerprint,
)
) {
private companion object {
- const val INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR =
- "Lapp/revanced/integrations/sponsorblock/PlayerController;"
+ const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/sponsorblock/SegmentPlaybackController;"
+ const val INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/sponsorblock/ui/CreateSegmentButtonController;"
+ const val INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/sponsorblock/ui/VotingButtonController;"
+ const val INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/sponsorblock/ui/SponsorBlockViewController;"
}
override fun execute(context: BytecodeContext): PatchResult {
/*
- Hook the video time methods
+ * Hook the video time methods
*/
with(VideoInformationPatch) {
videoTimeHook(
- INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR,
+ INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
"setVideoTime"
)
- highPrecisionTimeHook(
- INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR,
- "setHighPrecisionVideoTime"
- )
}
/*
- Set current video id
+ * Set current video id
*/
- VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
+ VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
/*
- Seekbar drawing
+ * Seekbar drawing
*/
val seekbarSignatureResult = SeekbarFingerprint.result!!.let {
SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) }
@@ -93,13 +100,13 @@ class SponsorBlockBytecodePatch : BytecodePatch(
val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions
/*
- Get the instance of the seekbar rectangle
+ * Get the instance of the seekbar rectangle
*/
for ((index, instruction) in seekbarMethodInstructions.withIndex()) {
if (instruction.opcode != Opcode.MOVE_OBJECT_FROM16) continue
seekbarMethod.addInstruction(
index + 1,
- "invoke-static/range {p0 .. p0}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V"
+ "invoke-static/range {p0 .. p0}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V"
)
break
}
@@ -115,14 +122,14 @@ class SponsorBlockBytecodePatch : BytecodePatch(
// set the thickness of the segment
seekbarMethod.addInstruction(
insertIndex,
- "invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V"
+ "invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V"
)
break
}
/*
- Set rectangle absolute left and right positions
- */
+ * Set rectangle absolute left and right positions
+ */
val drawRectangleInstructions = seekbarMethodInstructions.withIndex().filter { (_, instruction) ->
instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect"
}.map { (index, instruction) -> // TODO: improve code
@@ -136,27 +143,27 @@ class SponsorBlockBytecodePatch : BytecodePatch(
// the reason for that is that we get the index, add instructions and then the offset would be wrong
seekbarMethod.addInstruction(
indexLeft + 1,
- "invoke-static {v$rectangleLeftRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteLeft(Landroid/graphics/Rect;)V"
+ "invoke-static {v$rectangleLeftRegister}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteLeft(Landroid/graphics/Rect;)V"
)
seekbarMethod.addInstruction(
indexRight + 1,
- "invoke-static {v$rectangleRightRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteRight(Landroid/graphics/Rect;)V"
+ "invoke-static {v$rectangleRightRegister}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteRight(Landroid/graphics/Rect;)V"
)
/*
- Draw segment
- */
+ * Draw segment
+ */
val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2)
val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let {
it.registerC to it.registerE
}
seekbarMethod.addInstruction(
drawSegmentInstructionInsertIndex,
- "invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
+ "invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
)
/*
- Voting & Shield button
+ * Voting & Shield button
*/
val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult
@@ -181,8 +188,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
method.addInstructions(
moveResultInstructionIndex + 1, // insert right after moving the view to the register and use that register
"""
- invoke-static {v$inflatedViewRegister}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->initialize(Ljava/lang/Object;)V
- invoke-static {v$inflatedViewRegister}, Lapp/revanced/integrations/sponsorblock/VotingButton;->initialize(Ljava/lang/Object;)V
+ invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;)V
+ invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;)V
"""
)
}
@@ -193,8 +200,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
// change visibility of the buttons
invertVisibilityMethod.addInstructions(
0, """
- invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibilityNegatedImmediate(Z)V
- invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibilityNegatedImmediate(Z)V
+ invoke-static {p1}, $INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibilityNegatedImmediate(Z)V
+ invoke-static {p1}, $INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibilityNegatedImmediate(Z)V
""".trimIndent()
)
}
@@ -203,15 +210,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
}
// change visibility of the buttons
- PlayerControlsBytecodePatch.injectVisibilityCheckCall("Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibility(Z)V")
- PlayerControlsBytecodePatch.injectVisibilityCheckCall("Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibility(Z)V")
-
- // set SegmentHelperLayout.context to the player layout instance
- val instanceRegister = 0
- NextGenWatchLayoutFingerprint.result!!.mutableMethod.addInstruction(
- 3, // after super call
- "invoke-static/range {p$instanceRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->addSkipSponsorView15(Landroid/view/View;)V"
- )
+ PlayerControlsBytecodePatch.injectVisibilityCheckCall("$INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibility(Z)V")
+ PlayerControlsBytecodePatch.injectVisibilityCheckCall("$INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->changeVisibility(Z)V")
// append the new time to the player layout
val appendTimeFingerprintResult = AppendTimeFingerprint.result!!
@@ -221,18 +221,18 @@ class SponsorBlockBytecodePatch : BytecodePatch(
appendTimeFingerprintResult.mutableMethod.addInstructions(
appendTimePatternScanStartIndex + 2, """
- invoke-static {v$targetRegister}, Lapp/revanced/integrations/sponsorblock/SponsorBlockUtils;->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String;
+ invoke-static {v$targetRegister}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
"""
)
// initialize the player controller
- VideoInformationPatch.onCreateHook(INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR, "initialize")
+ VideoInformationPatch.onCreateHook(INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR, "initialize")
// initialize the sponsorblock view
PlayerOverlaysLayoutInitFingerprint.result!!.mutableMethod.addInstruction(
6, // after inflating the view
- "invoke-static {p0}, Lapp/revanced/integrations/sponsorblock/player/ui/SponsorBlockView;->initialize(Ljava/lang/Object;)V"
+ "invoke-static {p0}, $INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;)V"
)
// get rectangle field name
@@ -244,7 +244,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
// replace the "replaceMeWith*" strings
context
- .proxy(context.classes.first { it.type.endsWith("PlayerController;") })
+ .proxy(context.classes.first { it.type.endsWith("SegmentPlaybackController;") })
.mutableClass
.methods
.find { it.name == "setSponsorBarRect" }
@@ -268,6 +268,18 @@ class SponsorBlockBytecodePatch : BytecodePatch(
}
} ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings")
+
+ // The vote and create segment buttons automatically change their visibility when appropriate,
+ // but if buttons are showing when the end of the video is reached then they will not automatically hide.
+ // Add a hook to forcefully hide when the end of the video is reached.
+ AutoRepeatParentFingerprint.result ?: return AutoRepeatParentFingerprint.toErrorResult()
+ AutoRepeatFingerprint.also {
+ it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef)
+ }.result?.mutableMethod?.addInstruction(
+ 0,
+ "invoke-static {}, $INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->endOfVideoReached()V"
+ ) ?: return AutoRepeatFingerprint.toErrorResult()
+
// TODO: isSBChannelWhitelisting implementation
return PatchResultSuccess()
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt
index fb6f903cd..7c59a9ace 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt
@@ -95,7 +95,7 @@ class SponsorBlockResourcePatch : ResourcePatch {
if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button"))) continue
// voting button id from the voting button view from the youtube_controls_layout.xml host file
- val votingButtonId = "@+id/voting_button"
+ val votingButtonId = "@+id/sb_voting_button"
view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId
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 e6f87b66d..b65016ffb 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt
index 3a3b5c81b..573ed5cb2 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt
@@ -30,18 +30,17 @@ class SpoofAppVersionPatch : BytecodePatch(
SpoofAppVersionFingerprint
)
) {
- companion object {
- const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/SpoofAppVersionPatch"
- }
-
override fun execute(context: BytecodeContext): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_spoof_app_version",
StringResource("revanced_spoof_app_version_title", "Spoof app version"),
false,
- StringResource("revanced_spoof_app_version_summary_on", "Version spoofed to 17.30.34. If switched off, the old UI layout may remain until logging out or clearing app data"),
- StringResource("revanced_spoof_app_version_summary_off", "Version not spoofed")
+ StringResource("revanced_spoof_app_version_summary_on", "Version spoofed to 17.30.34"),
+ StringResource("revanced_spoof_app_version_summary_off", "Version not spoofed"),
+ StringResource("revanced_spoof_app_version_user_dialog_message",
+ "App version will be spoofed to 17.30.34. This will give the old UI layout, but unknown side effects may occur."
+ + " If later turned off, the old UI layout may remain until you log out or clear the app data.")
)
)
@@ -61,4 +60,8 @@ class SpoofAppVersionPatch : BytecodePatch(
return PatchResultSuccess()
}
+
+ private companion object {
+ const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/SpoofAppVersionPatch"
+ }
}
\ No newline at end of file
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 c5bdec69d..82c1b333b 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 e4629fb43..61651c1b5 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,19 +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(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
-)
+@Compatibility([Package("com.google.android.youtube", arrayOf("18.08.37"))])
@Target(AnnotationTarget.CLASS)
internal annotation class TabletMiniPlayerCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt
index a378eaf65..247655248 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt
@@ -7,7 +7,7 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
-@FuzzyPatternScanMethod(2) // TODO: Find a good threshold value
+@FuzzyPatternScanMethod(2)
object MiniPlayerDimensionsCalculatorFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
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
new file mode 100644
index 000000000..49a394933
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideParentFingerprint.kt
@@ -0,0 +1,13 @@
+package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
+
+import app.revanced.patcher.extensions.or
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.AccessFlags
+
+
+object MiniPlayerOverrideParentFingerprint : MethodFingerprint(
+ returnType = "L",
+ access = AccessFlags.PUBLIC or AccessFlags.STATIC,
+ parameters = listOf("L"),
+ strings = listOf("VIDEO_QUALITIES_QUICK_MENU_BOTTOM_SHEET_FRAGMENT")
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt
index 8c4269ee2..a290173e6 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt
@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.tabletminiplayer.patch
+import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -16,10 +17,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.layout.tabletminiplayer.annotations.TabletMiniPlayerCompatibility
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerDimensionsCalculatorFingerprint
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideFingerprint
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideNoContextFingerprint
-import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint
+import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.*
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@@ -33,7 +31,8 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
class TabletMiniPlayerPatch : BytecodePatch(
listOf(
MiniPlayerDimensionsCalculatorFingerprint,
- MiniPlayerResponseModelSizeCheckFingerprint
+ MiniPlayerResponseModelSizeCheckFingerprint,
+ MiniPlayerOverrideParentFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
@@ -47,33 +46,42 @@ class TabletMiniPlayerPatch : BytecodePatch(
)
)
- // first resolve the fingerprints via the parent fingerprint
+ // First resolve the fingerprints via the parent fingerprint.
val miniPlayerClass = MiniPlayerDimensionsCalculatorFingerprint.result!!.classDef
/*
- * no context parameter method
+ * No context parameter method.
*/
MiniPlayerOverrideNoContextFingerprint.resolve(context, miniPlayerClass)
val (method, _, parameterRegister) = MiniPlayerOverrideNoContextFingerprint.addProxyCall()
- // - 1 means to insert before the return instruction
+
+ // Insert right before the return instruction.
val secondInsertIndex = method.implementation!!.instructions.size - 1
- method.insertOverride(secondInsertIndex, parameterRegister /** same register used to return **/)
+ method.insertOverride(
+ secondInsertIndex, parameterRegister
+ /** same register used to return **/
+ )
/*
- * method with context parameter
+ * Method with context parameter.
*/
- MiniPlayerOverrideFingerprint.resolve(context, miniPlayerClass)
- val (_, _, _) = MiniPlayerOverrideFingerprint.addProxyCall()
+ MiniPlayerOverrideParentFingerprint.result?.let {
+ if (!MiniPlayerOverrideFingerprint.resolve(context, it.classDef))
+ return MiniPlayerOverrideFingerprint.toErrorResult()
+
+ MiniPlayerOverrideFingerprint.addProxyCall()
+
+ } ?: return MiniPlayerOverrideParentFingerprint.toErrorResult()
/*
- * size check return value override
+ * Size check return value override.
*/
- val (_, _, _) = MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall()
+ MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall()
return PatchResultSuccess()
}
- // helper methods
+ // Helper methods.
private companion object {
fun MethodFingerprint.addProxyCall(): Triple {
val (method, scanIndex, parameterRegister) = this.unwrap()
diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/annotations/WideSearchbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/annotations/WideSearchbarCompatibility.kt
deleted file mode 100644
index 30639b3b5..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/annotations/WideSearchbarCompatibility.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package app.revanced.patches.youtube.layout.widesearchbar.annotations
-
-import app.revanced.patcher.annotation.Compatibility
-import app.revanced.patcher.annotation.Package
-
-@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
-)
-@Target(AnnotationTarget.CLASS)
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class WideSearchbarCompatibility
\ 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 b6c421584..001061ae0 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt
index b3946737b..8a2a8c88e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt
@@ -11,15 +11,16 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.debugging.annotations.DebuggingCompatibility
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
+import app.revanced.patches.all.misc.debugging.patch.EnableAndroidDebuggingPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import org.w3c.dom.Element
@Patch
-@Name("debugging")
-@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
+@Name("enable-debugging")
+@DependsOn([IntegrationsPatch::class, SettingsPatch::class, EnableAndroidDebuggingPatch::class])
@Description("Adds debugging options.")
@DebuggingCompatibility
-@Version("0.0.1")
+@Version("0.0.2")
class DebuggingPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
@@ -52,36 +53,18 @@ class DebuggingPatch : ResourcePatch {
),
true,
StringResource("revanced_debug_toast_on_error_summary_on", "Toast shown if error occurs"),
- StringResource("revanced_debug_toast_on_error_summary_off", "Toast not shown if error occurs")
+ StringResource("revanced_debug_toast_on_error_summary_off", "Toast not shown if error occurs"),
+ StringResource("revanced_debug_toast_on_error_user_dialog_message",
+ "Turning off error toasts hides all ReVanced error notifications." +
+ " This includes hiding normal network connection timeouts, " +
+ "but also hides notification of any unexpected and more serious errors."
+ )
),
),
StringResource("revanced_debug_summary", "Enable or disable debugging options")
)
)
- if (debuggable == true) {
- context.xmlEditor["AndroidManifest.xml"].use { dom ->
- val applicationNode = dom
- .file
- .getElementsByTagName("application")
- .item(0) as Element
-
- // set application as debuggable
- applicationNode.setAttribute("android:debuggable", "true")
- }
- }
-
return PatchResultSuccess()
}
-
- companion object : OptionsContainer() {
- var debuggable: Boolean? by option(
- PatchOption.BooleanOption(
- key = "debuggable",
- default = false,
- title = "App debugging",
- description = "Whether to make the app debuggable on Android.",
- )
- )
- }
}
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 7ba4cfcf2..88d68b981 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotation/ProtobufSpoofCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotation/ProtobufSpoofCompatibility.kt
index 1f7d7513d..698a4f0bf 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotation/ProtobufSpoofCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotation/ProtobufSpoofCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt
index a8c48cbd1..32b094c14 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt
@@ -14,6 +14,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
+import app.revanced.patches.shared.misc.fix.spoof.patch.ClientSpoofPatch
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.fix.playback.annotation.ProtobufSpoofCompatibility
@@ -27,9 +28,14 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("spoof-signature-verification")
-@Description("Spoofs the client to prevent playback issues.")
+@Description("Spoofs a patched client to prevent playback issues.")
@ProtobufSpoofCompatibility
-@DependsOn([IntegrationsPatch::class, SettingsPatch::class, PlayerTypeHookPatch::class])
+@DependsOn([
+ IntegrationsPatch::class,
+ SettingsPatch::class,
+ PlayerTypeHookPatch::class,
+ ClientSpoofPatch::class
+])
@Version("0.0.1")
class SpoofSignatureVerificationPatch : BytecodePatch(
listOf(
@@ -45,7 +51,9 @@ class SpoofSignatureVerificationPatch : BytecodePatch(
StringResource("revanced_spoof_signature_verification_title", "Spoof app signature"),
true,
StringResource("revanced_spoof_signature_verification_summary_on", "App signature spoofed"),
- StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed")
+ StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed"),
+ StringResource("revanced_spoof_signature_verification_user_dialog_message",
+ "Signature spoofing can fix playback issues, but may causes side effects.")
)
)
@@ -107,7 +115,7 @@ class SpoofSignatureVerificationPatch : BytecodePatch(
return PatchResultSuccess()
}
- companion object {
+ private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/SpoofSignatureVerificationPatch;"
}
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt
index 1ff06a101..9c7bba1e2 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 293035d7e..96fc2e7fc 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt
index 730e856c1..be3b5d8b7 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt
@@ -3,5 +3,5 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints
import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint
object InitFingerprint : IntegrationsFingerprint(
- strings = listOf("Application creation"),
+ strings = listOf("Application creation", "Application.onCreate"),
)
\ 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 cb79ce80b..169c4dff8 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt
index e81e6ffc2..d89900243 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt
index 7f661ac49..a57ae700f 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt
@@ -5,13 +5,6 @@ import org.jf.dexlib2.Opcode
object ComponentContextParserFingerprint : MethodFingerprint(
opcodes = listOf(
- Opcode.INVOKE_INTERFACE,
- Opcode.MOVE_RESULT_OBJECT,
- Opcode.CHECK_CAST,
- Opcode.INVOKE_VIRTUAL,
- Opcode.GOTO,
- Opcode.INVOKE_VIRTUAL,
- Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt
index 1842275a5..7c77b9f96 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt
@@ -5,6 +5,7 @@ import org.jf.dexlib2.Opcode
object EmptyComponentBuilderFingerprint : MethodFingerprint(
opcodes = listOf(
+ Opcode.INVOKE_INTERFACE,
Opcode.INVOKE_STATIC_RANGE
),
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt
new file mode 100644
index 000000000..b78e48af1
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ReadComponentIdentifierFingerprint.kt
@@ -0,0 +1,12 @@
+package app.revanced.patches.youtube.misc.litho.filter.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object ReadComponentIdentifierFingerprint : MethodFingerprint(
+ opcodes = listOf(
+ Opcode.IF_NEZ,
+ null,
+ Opcode.MOVE_RESULT_OBJECT // Register stores the component identifier string
+ )
+)
\ 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 9ea24e433..96dfba82c 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
@@ -1,10 +1,12 @@
package app.revanced.patches.youtube.misc.litho.filter.patch
+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.addInstructions
import app.revanced.patcher.extensions.instruction
+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
@@ -16,12 +18,10 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.annotation.LithoFilterCompatibility
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ComponentContextParserFingerprint
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.EmptyComponentBuilderFingerprint
+import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ReadComponentIdentifierFingerprint
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.iface.instruction.TwoRegisterInstruction
-import org.jf.dexlib2.iface.reference.FieldReference
-import org.jf.dexlib2.iface.reference.MethodReference
@DependsOn([IntegrationsPatch::class])
@Description("Hooks the method which parses the bytes into a ComponentContext to filter components.")
@@ -31,33 +31,40 @@ class LithoFilterPatch : BytecodePatch(
listOf(ComponentContextParserFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
- ComponentContextParserFingerprint.result?.let { result ->
- val builderMethodIndex = EmptyComponentBuilderFingerprint
- .also { it.resolve(context, result.mutableMethod, result.mutableClass) }
- .let { it.result!!.scanResult.patternScanResult!!.startIndex }
-
+ ComponentContextParserFingerprint.result?.also {
+ arrayOf(EmptyComponentBuilderFingerprint, ReadComponentIdentifierFingerprint).forEach { fingerprint ->
+ if (!fingerprint.resolve(context, it.mutableMethod, it.mutableClass))
+ return fingerprint.toErrorResult()
+ }
+ }?.let { result ->
+ val builderMethodIndex = EmptyComponentBuilderFingerprint.patternScanEndIndex
val emptyComponentFieldIndex = builderMethodIndex + 2
- with(result.mutableMethod) {
+ result.mutableMethod.apply {
val insertHookIndex = result.scanResult.patternScanResult!!.endIndex
- val clobberedRegister = (instruction(insertHookIndex - 3) as OneRegisterInstruction).registerA
+ val builderMethodDescriptor = instruction(builderMethodIndex).descriptor
+ val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).descriptor
+ // Register is overwritten right after it is used for this patch, therefore free to clobber.
+ val clobberedRegister = instruction(insertHookIndex).oneRegister
- val builderMethodDescriptor = instruction(builderMethodIndex).toDescriptor()
- val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).toDescriptor()
+ @Suppress("UnnecessaryVariable")
+ // The register, this patch clobbers, is previously used for the StringBuilder,
+ // later on a new StringBuilder is instantiated on it.
+ val stringBuilderRegister = clobberedRegister
- val stringBuilderRegister = (instruction(insertHookIndex - 1) as TwoRegisterInstruction).registerA
+ val identifierRegister = instruction(ReadComponentIdentifierFingerprint.patternScanEndIndex).oneRegister
addInstructions(
insertHookIndex, // right after setting the component.pathBuilder field,
"""
- invoke-static {v$stringBuilderRegister, v0}, Lapp/revanced/integrations/patches/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
+ invoke-static {v$stringBuilderRegister, v$identifierRegister}, Lapp/revanced/integrations/patches/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
move-result v$clobberedRegister
if-eqz v$clobberedRegister, :not_an_ad
- move-object/from16 v0, p1
- invoke-static {v0}, $builderMethodDescriptor
- move-result-object v0
- iget-object v0, v0, $emptyComponentFieldDescriptor
- return-object v0
+ move-object/from16 v$clobberedRegister, p1
+ invoke-static {v$clobberedRegister}, $builderMethodDescriptor
+ move-result-object v$clobberedRegister
+ iget-object v$clobberedRegister, v$clobberedRegister, $emptyComponentFieldDescriptor
+ return-object v$clobberedRegister
""",
listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex)))
)
@@ -68,14 +75,14 @@ class LithoFilterPatch : BytecodePatch(
}
private companion object {
- fun Instruction.toDescriptor() = when (val reference = (this as? ReferenceInstruction)?.reference) {
- is MethodReference -> "${reference.definingClass}->${reference.name}(${
- reference.parameterTypes.joinToString(
- ""
- ) { it }
- })${reference.returnType}"
- is FieldReference -> "${reference.definingClass}->${reference.name}:${reference.type}"
- else -> throw PatchResultError("Unsupported reference type")
- }
+ val MethodFingerprint.patternScanEndIndex
+ get() = result!!.scanResult.patternScanResult!!.endIndex
+
+ val Instruction.descriptor
+ get() = (this as ReferenceInstruction).reference.toString()
+
+ val Instruction.oneRegister
+ get() = (this as OneRegisterInstruction).registerA
+
}
-}
+}
\ No newline at end of file
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 67884e5bd..65ffd1898 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/IntegrityCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/IntegrityCheckFingerprint.kt
deleted file mode 100644
index f3d41191b..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/IntegrityCheckFingerprint.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package app.revanced.patches.youtube.misc.microg.fingerprints
-
-import app.revanced.patcher.extensions.or
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import org.jf.dexlib2.AccessFlags
-
-object IntegrityCheckFingerprint : MethodFingerprint(
- "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"),
- strings = listOf("This should never happen.", "GooglePlayServicesUtil", "Google Play Store signature invalid.")
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt
index 22b1a65da..9a5926896 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt
@@ -10,8 +10,8 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.fingerprints.WatchWhileActivityFingerprint
-import app.revanced.patches.youtube.layout.buttons.cast.patch.HideCastButtonPatch
import app.revanced.patches.shared.misc.fix.spoof.patch.ClientSpoofPatch
+import app.revanced.patches.youtube.layout.buttons.cast.patch.HideCastButtonPatch
import app.revanced.patches.youtube.misc.fix.playback.patch.SpoofSignatureVerificationPatch
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
import app.revanced.patches.youtube.misc.microg.fingerprints.*
@@ -25,16 +25,14 @@ import app.revanced.util.microg.MicroGBytecodeHelper
[
MicroGResourcePatch::class,
HideCastButtonPatch::class,
- ClientSpoofPatch::class
]
)
-@Name("microg-support")
+@Name("vanced-microg-support")
@Description("Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.")
@MicroGPatchCompatibility
@Version("0.0.1")
class MicroGBytecodePatch : BytecodePatch(
listOf(
- IntegrityCheckFingerprint,
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
@@ -59,7 +57,6 @@ class MicroGBytecodePatch : BytecodePatch(
REVANCED_PACKAGE_NAME
),
listOf(
- IntegrityCheckFingerprint,
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
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 152e1844a..fe77a8aec 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt
deleted file mode 100644
index e25ef7823..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package app.revanced.patches.youtube.misc.openlinksdirectly.annotations
-
-import app.revanced.patcher.annotation.Compatibility
-import app.revanced.patcher.annotation.Package
-
-@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
-)
-@Target(AnnotationTarget.CLASS)
-@Retention(AnnotationRetention.RUNTIME)
-internal annotation class OpenLinksDirectlyCompatibility
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 0fb69614a..c5114acc6 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 98fb6a84b..c41ad4f16 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 99295a865..a54f3aada 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
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt
index 01c4c1087..1fceecd38 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt
@@ -10,16 +10,16 @@ object ThemeSetterAppFingerprint : MethodFingerprint(
AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L", "L", "L", "L"),
opcodes = listOf(
- Opcode.CONST, //target reference
+ Opcode.CONST, // target reference
Opcode.GOTO,
- Opcode.CONST, //target reference
+ Opcode.CONST, // target reference
Opcode.INVOKE_DIRECT,
Opcode.RETURN_OBJECT,
Opcode.NEW_INSTANCE,
- Opcode.INVOKE_INTERFACE,
+ null, // changed from invoke interface to invoke virtual
Opcode.MOVE_RESULT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IF_NE,
- Opcode.CONST, //target reference
+ Opcode.CONST, // target reference
)
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt
index eee608081..4248b6778 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt
@@ -18,6 +18,7 @@ import app.revanced.patches.shared.settings.resource.patch.AbstractSettingsResou
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.copyResources
+import app.revanced.util.resources.ResourceUtils.mergeStrings
import org.w3c.dom.Node
@Name("settings-resource-patch")
@@ -77,6 +78,8 @@ class SettingsResourcePatch : AbstractSettingsResourcePatch(
)
)
+ context.mergeStrings("settings/host/values/strings.xml")
+
return PatchResultSuccess()
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt
index d3e753234..d90f70008 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt
@@ -4,18 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
+ [Package("com.google.android.youtube", arrayOf("18.08.37"))]
)
@Target(AnnotationTarget.CLASS)
internal annotation class VideoInformationCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt
similarity index 55%
rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt
rename to src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt
index 059d31783..648f1a7e3 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/OnPlaybackSpeedItemClickFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt
@@ -1,4 +1,4 @@
-package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
+package app.revanced.patches.youtube.misc.video.information.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
@@ -6,7 +6,9 @@ import org.jf.dexlib2.Opcode
object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint(
customFingerprint = { it.name == "onItemClick" },
opcodes = listOf(
- Opcode.IGET_OBJECT,
- Opcode.INVOKE_VIRTUAL
+ Opcode.MOVE_RESULT_OBJECT,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.INVOKE_VIRTUAL,
+ Opcode.RETURN_VOID
)
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt
index 83a9333a0..77f44a9ed 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt
@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.misc.video.information.patch
+import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -20,10 +21,16 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility
import app.revanced.patches.youtube.misc.video.information.fingerprints.*
+import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.AccessFlags
+import org.jf.dexlib2.Opcode
+import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.MutableMethodImplementation
+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.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodParameter
import org.jf.dexlib2.util.MethodUtil
@@ -39,6 +46,7 @@ class VideoInformationPatch : BytecodePatch(
CreateVideoPlayerSeekbarFingerprint,
PlayerControllerSetTimeReferenceFingerprint,
VideoTimeFingerprint,
+ OnPlaybackSpeedItemClickFingerprint,
)
) {
override fun execute(context: BytecodeContext): PatchResult {
@@ -96,15 +104,15 @@ class VideoInformationPatch : BytecodePatch(
}
/*
- Inject call for video id
+ * Inject call for video id
*/
val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V"
VideoIdPatch.injectCall(videoIdMethodDescriptor)
VideoIdPatch.injectCallBackgroundPlay(videoIdMethodDescriptor)
/*
- Set the video time method
- */
+ * Set the video time method
+ */
with(PlayerControllerSetTimeReferenceFingerprint.result!!) {
timeMethod = context.toMethodWalker(method)
.nextMethod(scanResult.patternScanResult!!.startIndex, true)
@@ -112,7 +120,7 @@ class VideoInformationPatch : BytecodePatch(
}
/*
- Set the high precision video time method
+ * Set the high precision video time method
*/
highPrecisionTimeMethod =
(object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also {
@@ -120,9 +128,30 @@ class VideoInformationPatch : BytecodePatch(
}.result!!.mutableMethod
/*
- Hook the methods which set the time
+ * Hook the methods which set the time
*/
- highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
+ highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTimeHighPrecision")
+
+
+ /*
+ * Hook the user playback speed selection
+ */
+ OnPlaybackSpeedItemClickFingerprint.result?.apply {
+ speedSelectionInsertMethod = mutableMethod
+ speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3
+ speedSelectionValueRegister =
+ (mutableMethod.instruction(speedSelectionInsertIndex) as FiveRegisterInstruction).registerD
+
+ val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions
+ setPlaybackSpeedContainerClassFieldReference =
+ getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ)
+ setPlaybackSpeedClassFieldReference =
+ getReference(speedSelectionMethodInstructions, 1, Opcode.IGET)
+ setPlaybackSpeedMethodReference =
+ getReference(speedSelectionMethodInstructions, 2, Opcode.IGET)
+ } ?: return OnPlaybackSpeedItemClickFingerprint.toErrorResult()
+
+ userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
return PatchResultSuccess()
}
@@ -155,6 +184,7 @@ class VideoInformationPatch : BytecodePatch(
/**
* Hook the video time.
+ * The hook is usually called once per second.
*
* @param targetMethodClass The descriptor for the static method to invoke when the player controller is created.
* @param targetMethodName The name of the static method to invoke when the player controller is created.
@@ -167,6 +197,8 @@ class VideoInformationPatch : BytecodePatch(
/**
* Hook the high precision video time.
+ * The hooks is called extremely often (10 to 15 times a seconds), so use with caution.
+ * Note: the hook is usually called _off_ the main thread
*
* @param targetMethodClass The descriptor for the static method to invoke when the player controller is created.
* @param targetMethodName The name of the static method to invoke when the player controller is created.
@@ -182,5 +214,30 @@ class VideoInformationPatch : BytecodePatch(
TIME(2),
HIGH_PRECISION_TIME(0),
}
+
+ private fun getReference(instructions: List, offset: Int, opcode: Opcode) =
+ instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference
+
+ val Instruction.reference get() = (this as ReferenceInstruction).reference.toString()
+
+ private lateinit var speedSelectionInsertMethod: MutableMethod
+ private var speedSelectionInsertIndex = 0
+ private var speedSelectionValueRegister = 0
+
+ /**
+ * Hook the video speed selected by the user.
+ */
+ internal fun userSelectedPlaybackSpeedHook(targetMethodClass: String, targetMethodName: String) =
+ speedSelectionInsertMethod.addInstruction(
+ speedSelectionInsertIndex++,
+ "invoke-static {v$speedSelectionValueRegister}, $targetMethodClass->$targetMethodName(F)V"
+ )
+
+ /**
+ * Used by [RememberPlaybackSpeedPatch]
+ */
+ internal lateinit var setPlaybackSpeedContainerClassFieldReference: String
+ internal lateinit var setPlaybackSpeedClassFieldReference: String
+ internal lateinit var setPlaybackSpeedMethodReference: String
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt
index d37cab1d3..ffb5921b5 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt
@@ -4,18 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
+ [Package("com.google.android.youtube", arrayOf("18.08.37"))]
)
@Target(AnnotationTarget.CLASS)
internal annotation class RememberVideoQualityCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt
new file mode 100644
index 000000000..896b5de3e
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt
@@ -0,0 +1,14 @@
+package app.revanced.patches.youtube.misc.video.quality.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object SetQualityByIndexMethodClassFieldReferenceFingerprint : MethodFingerprint(
+ returnType = "V",
+ parameters = listOf("L"),
+ opcodes = listOf(
+ Opcode.IGET_OBJECT,
+ Opcode.INVOKE_INTERFACE,
+ Opcode.RETURN_VOID
+ )
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt
new file mode 100644
index 000000000..592c62fc0
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt
@@ -0,0 +1,9 @@
+
+package app.revanced.patches.youtube.misc.video.quality.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+
+object VideoQualityItemOnClickParentFingerprint : MethodFingerprint(
+ "V",
+ strings = listOf("VIDEO_QUALITIES_MENU_BOTTOM_SHEET_FRAGMENT")
+)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt
deleted file mode 100644
index 3ea366f78..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package app.revanced.patches.youtube.misc.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 VideoQualityReferenceFingerprint : MethodFingerprint(
- "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
- Opcode.IPUT_OBJECT, Opcode.RETURN_VOID
- )
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt
index db1853c17..9a29d162b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt
@@ -9,12 +9,13 @@ import org.jf.dexlib2.Opcode
object VideoQualitySetterFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
- listOf("[L", "I", "I", "Z", "I"),
+ listOf("[L", "I", "Z"),
listOf(
Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_BOOLEAN,
- )
+ ),
+ strings = listOf("menu_item_video_quality"),
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt
deleted file mode 100644
index 2575d5d3d..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-
-package app.revanced.patches.youtube.misc.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 VideoUserQualityChangeFingerprint : MethodFingerprint(
- "V",
- AccessFlags.PUBLIC or AccessFlags.FINAL,
- listOf("L","L","I","J"),
- listOf(
- Opcode.MOVE,
- Opcode.MOVE_WIDE,
- Opcode.INVOKE_INTERFACE_RANGE,
- Opcode.RETURN_VOID
- )
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt
index 416ef3f04..d5a03e33b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt
@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.misc.video.quality.patch
+import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -9,17 +10,20 @@ import app.revanced.patcher.extensions.addInstructions
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.patcher.patch.annotations.Patch
+import app.revanced.patches.shared.settings.preference.impl.ArrayResource
+import app.revanced.patches.shared.settings.preference.impl.ListPreference
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.video.quality.annotations.RememberVideoQualityCompatibility
-import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualityReferenceFingerprint
+import app.revanced.patches.youtube.misc.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint
+import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint
import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualitySetterFingerprint
-import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoUserQualityChangeFingerprint
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@@ -32,14 +36,18 @@ import org.jf.dexlib2.iface.reference.FieldReference
@Version("0.0.1")
class RememberVideoQualityPatch : BytecodePatch(
listOf(
- VideoQualitySetterFingerprint
+ VideoQualitySetterFingerprint,
+ VideoQualityItemOnClickParentFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference(
"revanced_remember_video_quality_last_selected",
- StringResource("revanced_remember_video_quality_last_selected_title", "Remember video quality changes"),
+ StringResource(
+ "revanced_remember_video_quality_last_selected_title",
+ "Remember video quality changes"
+ ),
true,
StringResource(
"revanced_remember_video_quality_last_selected_summary_on",
@@ -52,37 +60,126 @@ class RememberVideoQualityPatch : BytecodePatch(
)
)
- val setterMethod = VideoQualitySetterFingerprint.result!!
-
- VideoUserQualityChangeFingerprint.resolve(context, setterMethod.classDef)
- val userQualityMethod = VideoUserQualityChangeFingerprint.result!!
-
- VideoQualityReferenceFingerprint.resolve(context, setterMethod.classDef)
- val qualityFieldReference =
- VideoQualityReferenceFingerprint.result!!.method.let { method ->
- (method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
- }
-
- VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;->newVideoStarted(Ljava/lang/String;)V")
-
- val qIndexMethodName =
- context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
-
- setterMethod.mutableMethod.addInstructions(
- 0,
- """
- iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
- const-string v1, "$qIndexMethodName"
- invoke-static {p1, p2, v0, v1}, Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
- move-result p2
- """,
+ // This is bloated as each value has it's own String key/value
+ // ideally the entries would be raw values (and not a key to a String resource)
+ val entries = listOf(
+ StringResource("revanced_default_quality_entry_1", "Automatic quality"),
+ StringResource("revanced_default_quality_entry_2", "2160p"),
+ StringResource("revanced_default_quality_entry_3", "1440p"),
+ StringResource("revanced_default_quality_entry_4", "1080p"),
+ StringResource("revanced_default_quality_entry_5", "720p"),
+ StringResource("revanced_default_quality_entry_6", "480p"),
+ StringResource("revanced_default_quality_entry_7", "360p"),
+ StringResource("revanced_default_quality_entry_8", "280p"),
+ StringResource("revanced_default_quality_entry_9", "144p"),
+ )
+ val entryValues = listOf(
+ StringResource("revanced_default_quality_entry_value_1", "-2"),
+ StringResource("revanced_default_quality_entry_value_2", "2160"),
+ StringResource("revanced_default_quality_entry_value_3", "1440"),
+ StringResource("revanced_default_quality_entry_value_4", "1080"),
+ StringResource("revanced_default_quality_entry_value_5", "720"),
+ StringResource("revanced_default_quality_entry_value_6", "480"),
+ StringResource("revanced_default_quality_entry_value_7", "360"),
+ StringResource("revanced_default_quality_entry_value_8", "280"),
+ StringResource("revanced_default_quality_entry_value_9", "144"),
+ )
+ SettingsPatch.PreferenceScreen.MISC.addPreferences(
+ ListPreference(
+ "revanced_default_video_quality_wifi",
+ StringResource(
+ "revanced_default_video_quality_wifi_title",
+ "Default video quality on Wi-Fi network"
+ ),
+ ArrayResource("revanced_video_quality_wifi_entry", entries),
+ ArrayResource("revanced_video_quality_wifi_entry_values", entryValues)
+ // default value and summary are set by integrations after loading
+ ),
+ ListPreference(
+ "revanced_default_video_quality_mobile",
+ StringResource(
+ "revanced_default_video_quality_mobile_title",
+ "Default video quality on mobile network"
+ ),
+ ArrayResource("revanced_video_quality_mobile_entries", entries),
+ ArrayResource("revanced_video_quality_mobile_entry_values", entryValues)
+ )
)
- userQualityMethod.mutableMethod.addInstruction(
- 0,
- "invoke-static {p3}, Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;->userChangedQuality(I)V"
- )
+ /*
+ * The following code works by hooking the method which is called when the user selects a video quality
+ * to remember the last selected video quality.
+ *
+ * It also hooks the method which is called when the video quality to set is determined.
+ * Conveniently, at this point the video quality is overridden to the remembered playback speed.
+ */
+ VideoIdPatch.injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
+
+ // Inject a call to set the remembered quality once a video loads.
+ VideoQualitySetterFingerprint.result?.also {
+ if (!SetQualityByIndexMethodClassFieldReferenceFingerprint.resolve(context, it.classDef))
+ return PatchResultError("Could not resolve fingerprint to find setQualityByIndex method")
+ }?.let {
+ // This instruction refers to the field with the type that contains the setQualityByIndex method.
+ val instructions = SetQualityByIndexMethodClassFieldReferenceFingerprint.result!!
+ .method.implementation!!.instructions
+
+ val getOnItemClickListenerClassReference =
+ (instructions.elementAt(0) as ReferenceInstruction).reference
+ val getSetQualityByIndexMethodClassFieldReference =
+ (instructions.elementAt(1) as ReferenceInstruction).reference
+
+ val setQualityByIndexMethodClassFieldReference =
+ getSetQualityByIndexMethodClassFieldReference as FieldReference
+
+ val setQualityByIndexMethodClass = context.classes
+ .find { classDef -> classDef.type == setQualityByIndexMethodClassFieldReference.type }!!
+
+ // Get the name of the setQualityByIndex method.
+ val setQualityByIndexMethod = setQualityByIndexMethodClass.methods
+ .find { method -> method.parameterTypes.first() == "I" }
+ ?: return PatchResultError("Could not find setQualityByIndex method")
+
+ it.mutableMethod.addInstructions(
+ 0,
+ """
+ # Get the object instance to invoke the setQualityByIndex method on.
+ iget-object v0, p0, $getOnItemClickListenerClassReference
+ iget-object v0, v0, $getSetQualityByIndexMethodClassFieldReference
+
+ # Get the method name.
+ const-string v1, "${setQualityByIndexMethod.name}"
+
+ # Set the quality.
+ # The first parameter is the array list of video qualities.
+ # The second parameter is the index of the selected quality.
+ # The register v0 stores the object instance to invoke the setQualityByIndex method on.
+ # The register v1 stores the name of the setQualityByIndex method.
+ invoke-static {p1, p2, v0, v1}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
+ move-result p2
+ """,
+ )
+ } ?: return VideoQualitySetterFingerprint.toErrorResult()
+
+ // Inject a call to remember the selected quality.
+ VideoQualityItemOnClickParentFingerprint.result?.let {
+ val onItemClickMethod = it.mutableClass.methods.find { method -> method.name == "onItemClick" }
+
+ onItemClickMethod?.apply {
+ val listItemIndexParameter = 3
+
+ addInstruction(
+ 0,
+ "invoke-static {p$listItemIndexParameter}, $INTEGRATIONS_CLASS_DESCRIPTOR->userChangedQuality(I)V"
+ )
+ } ?: return PatchResultError("Failed to find onItemClick method")
+ } ?: return VideoQualityItemOnClickParentFingerprint.toErrorResult()
return PatchResultSuccess()
}
+
+ private companion object {
+ const val INTEGRATIONS_CLASS_DESCRIPTOR =
+ "Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;"
+ }
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt
index 2d57cecc6..1cb9593e0 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt
index 1b76883b7..c038ba497 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt
@@ -9,11 +9,11 @@ import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.*
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.misc.video.speed.custom.annotations.CustomPlaybackSpeedCompatibility
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedLimiterFingerprint
import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.VideoSpeedPatchFingerprint
-import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import org.jf.dexlib2.builder.instruction.BuilderArrayPayload
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt
index ea47d1e68..39a5f7a9b 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt
@@ -4,18 +4,7 @@ import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
- [Package(
- "com.google.android.youtube", arrayOf(
- "17.49.37",
- "18.03.36",
- "18.03.42",
- "18.04.35",
- "18.04.41",
- "18.05.32",
- "18.05.35",
- "18.05.40"
- )
- )]
+ [Package("com.google.android.youtube", arrayOf("18.08.37"))]
)
@Target(AnnotationTarget.CLASS)
internal annotation class RememberPlaybackSpeedCompatibility
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackSpeedFragmentStateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackSpeedFragmentStateFingerprint.kt
deleted file mode 100644
index cb1aca4f6..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/ChangePlaybackSpeedFragmentStateFingerprint.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
-
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-
-object ChangePlaybackSpeedFragmentStateFingerprint : MethodFingerprint(
- "V",
- strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
-)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt
index 140e243cb..e244a298e 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt
@@ -3,5 +3,6 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object InitializePlaybackSpeedValuesFingerprint : MethodFingerprint(
- parameters = listOf("[L", "I")
+ parameters = listOf("[L", "I"),
+ strings = listOf("menu_item_playback_speed")
)
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt
index ecd909fc0..4895e665a 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt
@@ -5,36 +5,34 @@ 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.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
-import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.*
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.ArrayResource
+import app.revanced.patches.shared.settings.preference.impl.ListPreference
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
+import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
+import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference
import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
-import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackSpeedFragmentStateFingerprint
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
-import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackSpeedItemClickFingerprint
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
-import org.jf.dexlib2.Opcode
-import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
-import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@Patch
@Name("remember-playback-speed")
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
-@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class])
+@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class, VideoInformationPatch::class])
@RememberPlaybackSpeedCompatibility
@Version("0.0.1")
class RememberPlaybackSpeedPatch : BytecodePatch(
- listOf(ChangePlaybackSpeedFragmentStateFingerprint)
+ listOf(
+ InitializePlaybackSpeedValuesFingerprint
+ )
) {
override fun execute(context: BytecodeContext): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
@@ -56,63 +54,66 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
)
)
- context.resolveFingerprints()
+ SettingsPatch.PreferenceScreen.MISC.addPreferences(
+ ListPreference(
+ "revanced_default_playback_speed",
+ StringResource(
+ "revanced_default_playback_speed_title",
+ "Default playback speed"
+ ),
+ // Dummy data:
+ // Entries and values are set by Integrations code based on the actual speeds available,
+ // and the values set here are ignored and do nothing.
+ ArrayResource(
+ "revanced_default_playback_speed_entries",
+ listOf(StringResource("revanced_default_playback_speed_entry", "1.0x"))
+ ),
+ ArrayResource(
+ "revanced_default_playback_speed_entry_values",
+ listOf(StringResource("revanced_default_playback_speed_entry_value", "1.0"))
+ )
+ )
+ )
VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V")
- // Set the remembered playback speed.
- InitializePlaybackSpeedValuesFingerprint.result!!.apply {
- // Infer everything necessary for setPlaybackSate()
+ VideoInformationPatch.userSelectedPlaybackSpeedHook(
+ INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
- val playbackHandlerWrapperFieldReference =
- (object : MethodFingerprint(opcodes = listOf(Opcode.IF_EQZ)) {}).apply {
- OnPlaybackSpeedItemClickFingerprint.result!!.apply {
- resolve(
- context,
- method,
- classDef
- )
- }
- }.getReference(-1)
- val playbackHandlerWrapperImplementorClassReference = OnPlaybackSpeedItemClickFingerprint
- .getReference(-1)
- val playbackHandlerFieldReference = OnPlaybackSpeedItemClickFingerprint
- .getReference()
- val setPlaybackSpeedMethodReference = OnPlaybackSpeedItemClickFingerprint
- .getReference(1)
+ /*
+ * Hook the code that is called when the playback speeds are initialized, and sets the playback speed
+ */
+ InitializePlaybackSpeedValuesFingerprint.result?.apply {
+ // Infer everything necessary for calling the method setPlaybackSpeed().
+ val onItemClickListenerClassFieldReference = mutableMethod.instruction(0).reference
+ // Registers are not used at index 0, so they can be freely used.
mutableMethod.addInstructions(
0,
"""
- invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getCurrentPlaybackSpeed()F
+ invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getPlaybackSpeedOverride()F
move-result v0
- # check if the playback speed is not 1.0x
+
+ # Check if the playback speed is not 1.0x.
const/high16 v1, 0x3f800000 # 1.0f
cmpg-float v1, v0, v1
if-eqz v1, :do_not_override
+
+ # Get the instance of the class which has the container class field below.
+ iget-object v1, p0, $onItemClickListenerClassFieldReference
- # invoke setPlaybackSpeed
- iget-object v1, p0, $playbackHandlerWrapperFieldReference
- check-cast v1, $playbackHandlerWrapperImplementorClassReference
- iget-object v2, v1, $playbackHandlerFieldReference
- invoke-virtual {v2, v0}, $setPlaybackSpeedMethodReference
+ # Get the container class field.
+ iget-object v1, v1, ${VideoInformationPatch.setPlaybackSpeedContainerClassFieldReference}
+
+ # Get the field from its class.
+ iget-object v2, v1, ${VideoInformationPatch.setPlaybackSpeedClassFieldReference}
+
+ # Invoke setPlaybackSpeed on that class.
+ invoke-virtual {v2, v0}, ${VideoInformationPatch.setPlaybackSpeedMethodReference}
""".trimIndent(),
listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0)))
)
- }
-
- // Remember the selected playback speed.
- OnPlaybackSpeedItemClickFingerprint.result!!.apply {
- val setPlaybackSpeedIndex = scanResult.patternScanResult!!.endIndex
- val selectedPlaybackSpeedRegister =
- (mutableMethod.instruction(setPlaybackSpeedIndex) as FiveRegisterInstruction).registerD
-
- mutableMethod.addInstruction(
- setPlaybackSpeedIndex,
- "invoke-static { v$selectedPlaybackSpeedRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V"
- )
- }
-
+ } ?: return InitializePlaybackSpeedValuesFingerprint.toErrorResult()
return PatchResultSuccess()
}
@@ -120,21 +121,5 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
-
- fun MethodFingerprint.getReference(offsetFromPatternScanResultStartIndex: Int = 0) = this.result!!.let {
- val referenceInstruction = it.mutableMethod
- .instruction(it.scanResult.patternScanResult!!.startIndex + offsetFromPatternScanResultStartIndex) as ReferenceInstruction
- referenceInstruction.reference.toString()
- }
-
- fun BytecodeContext.resolveFingerprints() {
- ChangePlaybackSpeedFragmentStateFingerprint.result?.also {
- fun MethodFingerprint.resolve() = resolve(this@resolveFingerprints, it.classDef)
-
- OnPlaybackSpeedItemClickFingerprint.resolve()
- InitializePlaybackSpeedValuesFingerprint.resolve()
-
- } ?: throw ChangePlaybackSpeedFragmentStateFingerprint.toErrorResult()
- }
}
-}
+}
\ No newline at end of file
diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt
index 777e015c1..35ba3251a 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt
@@ -6,14 +6,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
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 5139f029f..98e8f802b 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
@@ -7,14 +7,15 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
- "17.49.37",
+ "17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
- "18.05.40"
+ "18.05.40",
+ "18.08.37"
)
)]
)
diff --git a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt
index c820e1e46..09fd98117 100644
--- a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt
@@ -35,7 +35,7 @@ class HideAdsPatch : BytecodePatch(
val adsListRegister = (instruction(insertIndex - 2) as Instruction21c).registerA
listOf(
- "video_display_full_buttoned_layout",
+ "_buttoned_layout",
"full_width_square_image_layout",
"_ad_with",
"landscape_image_wide_button_layout",
@@ -46,7 +46,8 @@ class HideAdsPatch : BytecodePatch(
"video_display_full_layout",
"hero_promo_image",
"statement_banner",
- "primetime_promo"
+ "primetime_promo",
+ "carousel_footered_layout"
).forEach { component ->
addInstructions(
insertIndex, """
@@ -60,4 +61,4 @@ class HideAdsPatch : BytecodePatch(
return PatchResultSuccess()
}
-}
\ No newline at end of file
+}
diff --git a/src/main/resources/returnyoutubedislike/host/values/strings.xml b/src/main/resources/returnyoutubedislike/host/values/strings.xml
index e97bbbc1f..31ca93597 100644
--- a/src/main/resources/returnyoutubedislike/host/values/strings.xml
+++ b/src/main/resources/returnyoutubedislike/host/values/strings.xml
@@ -21,6 +21,7 @@
Like button styled for minimum width
Like button styled for best appearance
+ About
ReturnYouTubeDislike.com
Dislike data is provided by the Return YouTube Dislike API. Tap here to learn more.
diff --git a/src/main/resources/settings/host/values/strings.xml b/src/main/resources/settings/host/values/strings.xml
new file mode 100644
index 000000000..c0740672f
--- /dev/null
+++ b/src/main/resources/settings/host/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Do you wish to proceed?
+
diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml b/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml
index 97db9c98d..30224f149 100644
--- a/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml
+++ b/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml
@@ -1,9 +1,9 @@
-
+ android:height="24dp"
+ android:tint="#FFFFFF"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
diff --git a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml
index 97796266a..33a11b83b 100644
--- a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml
+++ b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml
@@ -1,4 +1,28 @@
-
-
-
+
+
+
+
+
diff --git a/src/main/resources/sponsorblock/host/values/strings.xml b/src/main/resources/sponsorblock/host/values/strings.xml
index 2f4838352..6ea734421 100644
--- a/src/main/resources/sponsorblock/host/values/strings.xml
+++ b/src/main/resources/sponsorblock/host/values/strings.xml
@@ -1,142 +1,179 @@
- Enable SponsorBlock
- SponsorBlock is a crowd-sourced system for skipping annoying parts in YouTube videos
- Enable new segment adding
- Switch this on to enable experimental segment adding (has button visibility issues)
- What to do with different segments
- General
- Show a toast when skipping segment automatically
- Click to see an example toast
- Skip count tracking
- This lets SponsorBlock leaderboard system know how much time people have saved. The extension sends a message to the server each time you skip a segment
- Adjusting new segment step
- This is the number of milliseconds you can move when you use the time adjustment buttons while adding new segment
- Minimum segment duration
- Segments shorter than the set value (in seconds) will not be skipped or shown in the player
- Your private user id
- This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you
- Import/Export settings
- This is your entire configuration that is applicable in the desktop extension in JSON. This includes your Private userID, so be sure to share this wisely.
- Change API URL
- The address SponsorBlock uses to make calls to the server. <b>Don\'t change this unless you know what you\'re doing.</b>
- Settings were successfully imported
- Failed to import settings
- Failed to export settings
- Cache segments locally
- Frequently watched videos (eg. music videos) may store segments in app cache to make skipping segments faster
- Clear SponsorBlock segments cache
- Sponsor
- Paid promotion, paid referrals and direct advertisements
- Intermission/Intro Animation
- An interval without actual content. Could be a pause, static frame, repeating animation
- Endcards/Credits
- Credits or when the YouTube endcards appear. Not for spoken conclusions
- Interaction Reminder (Subscribe)
- When there is a short reminder to like, subscribe, follow or interact with them on any free or paid platform
- Unpaid/Self Promotion
- When there is unpaid or self promotion. This includes specific sections about merchandise, donations, or information about who they collaborated with
- Music: Non-Music Section
- Only for use in music videos. Skips parts of the video not in official mixes
- Filler Tangent/Jokes
- Tangential scenes added only for filler or humor that are not required to understand the main content of the video. This should not include context or background details
- Skipped a sponsor segment
- Skipped sponsor
- Skipped intro
- Skipped outro
- Skipped annoying reminder
- Skipped self promotion
- Skipped a non-music section
- Skipped preview
- Skipped filler
- Skipped unsubmitted segment
- Skip automatically
- Skip automatically once
- Show a skip button
- Don\'t do anything
- Skip segment
- About
- This app uses the API from SponsorBlock
- Tap to learn more, and see downloads for other platforms at: sponsor.ajay.app
- Integration made by JakubWeg, recoded by oSumAtrIX
- Tap to skip
+ Enable SponsorBlock
+ SponsorBlock is a crowd-sourced system for skipping annoying parts of YouTube videos
+ Show voting button
+ Segment voting button is shown
+ Segment voting button is not shown
+ Show create new segment button
+ Create new segment button is shown
+ Create new segment button is not shown
+ Use compact skip button
+ Skip button styled for minimum width
+ Skip button styled for best appearance
+ What to do with different segments
+ General
+ Show a toast when skipping segment automatically
+ Toast shown when a segment is automatically skipped. Tap here to see an example
+ Toast not shown. Tap here to see an example
+ Enable skip count tracking
+ Lets the SponsorBlock leaderboard know how much time is saved. A message is sent to the leaderboard each time a segment is skipped
+ Skip count tracking is not enabled
+ Show video length without segments
+ Video length minus all segments, shown in parentheses next to the full video length
+ Full video length shown
+ Adjust new segment step
+ Number of milliseconds the time adjustment buttons move when creating new segments
+ Value must be a positive number
+ Minimum segment duration
+ Segments shorter than this value (in seconds) will not be shown or skipped
+ Your private user id
+ This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you
+ User id cannot be blank
+ Import/Export settings
+ Your SponsorBlock JSON configuration that can be imported/exported to ReVanced and other SponsorBlock platforms. This includes your private user id. Be sure to share this wisely
+ Change API URL
+ The address SponsorBlock uses to make calls to the server. <b>Don\'t change this unless you know what you\'re doing</b>
+ Settings imported successfully
+ Failed to import: %s
+ Failed to export settings (try clearing app data)
- Can\'t submit the segment: %s
- Unable to submit segments: Status: %d %s
- Can\'t submit the segment.\nRate Limited (Too many from the same user or IP)
- Can\'t submit the segment.\n\n%s
- Can\'t submit the segment.\nAlready exists
- Segment submitted successfully
- Submitting segmentβ¦
+ Sponsor
+ Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free shout-outs to causes/creators/websites/products they like
+ Unpaid/Self Promotion
+ Similar to \'Sponsor\' except for unpaid or self promotion. Includes sections about merchandise, donations, or information about who they collaborated with
+ Interaction Reminder (Subscribe)
+ A short reminder to like, subscribe or follow them in the middle of content. If it is long or about something specific, it should instead be under self promotion
+ Highlight
+ The part of the video that most people are looking for
+ Intermission/Intro Animation
+ An interval without actual content. Could be a pause, static frame, or repeating animation. Does not include transitions containing information
+ Endcards/Credits
+ Credits or when the YouTube endcards appear. Not for conclusions with information
+ Preview/Recap
+ Collection of clips that show what is coming up or what happened in the video or in other videos of a series, where all information is repeated elsewhere
+ Filler Tangent/Jokes
+ Tangential scenes added only for filler or humor that are not required to understand the main content of the video. Does not include segments providing context or background details
+ Music: Non-Music Section
+ Only for use in music videos. Sections of music videos without music, that aren\'t already covered by another category
- Unable to vote for segment: Status: %d %s
- Can\'t vote for segment.\nRate Limited (Too many from the same user or IP)
- Can\'t vote for segment.\n\n%s
- Voted successfully
- Voting for segmentβ¦
- Upvote
- Downvote
- Change category
- There are no segments to vote for
- Enable voting
- Switch this on to enable voting.
+ Skip
+ Highlight
+ Skip sponsor
+ Skip promo
+ Skip interact
+ Skip to highlight
+ Skip intro
+ Skip intermission
+ Skip intermission
+ Skip outro
+ Skip preview
+ Skip preview
+ Skip recap
+ Skip filler
+ Skip non-music
+ Skip segment
- Choose the segment category
- You\'ve disabled this category in the settings, enable it to be able to submit
- New SponsorBlock segment
- Set %02d:%02d:%04d as the start or end of a new segment?
- start
- end
- now
- Time the segment begins at
- Time the segment ends at
- Beginning of segment set
- End of segment set
- Are the times correct?
- The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds)\nIs it ready to submit?
- Mark two locations on the time bar first
- Edit timing of segment manually
- Do you want to edit the timing for the start or end of the segment?
- Done
- Invalid time given
+ Skipped sponsor
+ Skipped self promotion
+ Skipped annoying reminder
+ Skipped to highlight
+ Skipped intro
+ Skipped intermission
+ Skipped intermission
+ Skipped outro
+ Skipped preview
+ Skipped preview
+ Skipped recap
+ Skipped filler
+ Skipped a non-music section
+ Skipped unsubmitted segment
+ Skipped multiple segments
+
+ Skip automatically
+ Skip automatically once
+ Show a skip button
+ Show in seek bar
+ Disable
+
+ 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
+
+ Can\'t submit the segment: %s
+ Unable to submit segments (API timed out)
+ Unable to submit segments (status: %d %s)
+ Can\'t submit the segment.\nRate Limited (too many from the same user or IP)
+ Can\'t submit the segment: %s
+ Can\'t submit the segment.\nAlready exists
+ Segment submitted successfully
+
+ SponsorBlock temporarily not available
+ SponsorBlock temporarily not available (status %d)
+ SponsorBlock temporarily not available (API timed out)
+
+ Unable to vote for segment (API timed out)
+ Unable to vote for segment (status: %d %s)
+ Unable to vote for segment: %s
+ Upvote
+ Downvote
+ Change category
+ There are no segments to vote for
+
+ Choose the segment category
+ Category is disabled in settings. Enable category to submit.
+ New SponsorBlock segment
+ Set %02d:%02d:%03d as the start or end of a new segment?
+ start
+ end
+ now
+ Time the segment begins at
+ Time the segment ends at
+ Are the times correct?
+ The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds)\nIs it ready to submit?
+ Start must be before the end
+ Mark two locations on the time bar first
+ Preview the segment, and ensure it skips smoothly
+ Edit timing of segment manually
+ Do you want to edit the timing for the start or end of the segment?
+ Invalid time given
View guidelines
- Guidelines contain tips and rules about submitting segments
- There are guidelines
- It\'s recommended to read the SponsorBlock guidelines before submitting any segment
+ Guidelines contain rules and tips for creating new segments
+ Follow the guidelines
+ Read the SponsorBlock guidelines before creating new segments
Already read
Show me
- Show time without segments
- This time appears in brackets next to the current time. This shows the total video duration minus any segments.
- Preview/Recap
- Recap of previous episodes, or a preview of what\'s coming up later in the current video or future videos in the same series. Clips should not provide additional information.
- Stats
- Loading..
- SponsorBlock is disabled
- Your username: <b>%s</b>
- Click to change your username
- Unable to change username: Status: %d %s
- Username successfully changed
- Submissions: <b>%s</b>
- You\'ve saved people from <b>%s</b> segments.
- That\'s <b>%s</b> of their lives. Click to see the leaderboard
- You\'ve skipped <b>%s</b> segments.
- That\'s <b>%s</b>.
- minutes
- Are you looking for changing colors?
- You can now change a category\'s color by clicking on it above.
- Choose the category
- Color changed
- Color reset
- Invalid hex code
- Change
- Reset
+ Stats
+ Stats temporarily not available (API is down)
+ Loading...
+ SponsorBlock is disabled
+ Your username: <b>%s</b>
+ Tap here to change your username
+ Unable to change username: Status: %d %s
+ Username successfully changed
+ You\'re reputation is <b>%.2f</b>
+ You\'ve created <b>%s</b> segments
+ SponsorBlock leaderboard
+ You\'ve saved people from <b>%s</b> segments
+ Tap here to see the global stats and top contributors
+ That\'s <b>%s</b> of their lives.<br>Tap here to see the leaderboard
+ You\'ve skipped <b>%s</b> segments
+ That\'s <b>%s</b>
+ Reset skipped segments counter?
+ %d hours %d minutes
+ %d minutes %d seconds
+ %d seconds
+ Color:
+ Color changed
+ Color reset
+ Invalid color code
+ Reset color
- Segments
- SB Browser
-
- API URL changed
- API URL reset
- Provided API URL is invalid
+ Reset
+ API URL reset
+ API URL is invalid
+ API URL changed
diff --git a/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml b/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml
index 6bc670fb9..2c0385549 100644
--- a/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml
+++ b/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml
@@ -1,5 +1,35 @@
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/sponsorblock/layout/new_segment.xml b/src/main/resources/sponsorblock/layout/new_segment.xml
index 155907c96..be5020be2 100644
--- a/src/main/resources/sponsorblock/layout/new_segment.xml
+++ b/src/main/resources/sponsorblock/layout/new_segment.xml
@@ -3,58 +3,58 @@
xmlns:yt="http://schemas.android.com/apk/res-auto">
+ android:layout_height="wrap_content"
+ android:background="#66000000"
+ android:gravity="start|center"
+ android:orientation="vertical">
+ android:paddingTop="3.0dip"
+ android:paddingEnd="5.0dip"
+ android:paddingBottom="3.0dip"
+ android:src="@drawable/player_fast_rewind" />
+ android:paddingTop="3.0dip"
+ android:paddingEnd="5.0dip"
+ android:paddingBottom="3.0dip"
+ android:src="@drawable/player_fast_forward" />
+ android:paddingTop="3.0dip"
+ android:paddingEnd="10.0dip"
+ android:paddingBottom="3.0dip"
+ android:src="@drawable/ic_sb_adjust" />
+ android:paddingTop="3.0dip"
+ android:paddingEnd="5.0dip"
+ android:paddingBottom="3.0dip"
+ android:src="@drawable/ic_sb_compare" />
+ android:paddingTop="3.0dip"
+ android:paddingEnd="5.0dip"
+ android:paddingBottom="3.0dip"
+ android:src="@drawable/ic_sb_edit" />
+ android:paddingTop="3.0dip"
+ android:paddingEnd="10.0dip"
+ android:paddingBottom="3.0dip"
+ android:src="@drawable/ic_sb_publish" />
\ No newline at end of file
diff --git a/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml b/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml
index 3ceb8c362..185960ec9 100644
--- a/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml
+++ b/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml
@@ -1,7 +1,35 @@
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file