mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-21 18:03:56 +00:00
Compare commits
22 Commits
v2.174.0-d
...
v2.174.0-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba52570ad6 | ||
|
|
bb303713bd | ||
|
|
1541e73e92 | ||
|
|
1d707b07b4 | ||
|
|
79e36e2b74 | ||
|
|
46552a5ab8 | ||
|
|
529e90d232 | ||
|
|
c72fd1e2fc | ||
|
|
48965ace7e | ||
|
|
08f1702b18 | ||
|
|
45784eceee | ||
|
|
f891aa937c | ||
|
|
aa493c4f67 | ||
|
|
a83e0dc257 | ||
|
|
5ea4d3c2a6 | ||
|
|
f4ae7fd9d7 | ||
|
|
b6539922fe | ||
|
|
a697b16aa3 | ||
|
|
ab22794ef2 | ||
|
|
cd6988a688 | ||
|
|
74ad4fa5ea | ||
|
|
382c441de5 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
- name: Setup JDK
|
- name: Setup JDK
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
java-version: '11'
|
java-version: '17'
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
cache: gradle
|
cache: gradle
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
|
|||||||
70
CHANGELOG.md
70
CHANGELOG.md
@@ -1,3 +1,73 @@
|
|||||||
|
# [2.174.0-dev.23](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.22...v2.174.0-dev.23) (2023-05-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **youtube/custom-video-speed:** add missing class for `video-speeds` patch ([#2137](https://github.com/revanced/revanced-patches/issues/2137)) ([758ef42](https://github.com/revanced/revanced-patches/commit/758ef42f9cd36d665b1737b67bcdde22d3e3eb98))
|
||||||
|
|
||||||
|
# [2.174.0-dev.22](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.21...v2.174.0-dev.22) (2023-05-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **youtube:** move video settings to `Video` settings category ([#2010](https://github.com/revanced/revanced-patches/issues/2010)) ([f4b9180](https://github.com/revanced/revanced-patches/commit/f4b918075a70d1a4ed9ac7e9c1f0e0acd1c77404))
|
||||||
|
|
||||||
|
# [2.174.0-dev.21](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.20...v2.174.0-dev.21) (2023-05-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **twitch:** add `auto-claim-channel-points` patch ([#2131](https://github.com/revanced/revanced-patches/issues/2131)) ([80fb670](https://github.com/revanced/revanced-patches/commit/80fb6701b52a8c6c6bada5546dffe3438f0e4879))
|
||||||
|
|
||||||
|
# [2.174.0-dev.20](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.19...v2.174.0-dev.20) (2023-05-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **youtube:** add `hide-filter-bar` patch ([6cc5f61](https://github.com/revanced/revanced-patches/commit/6cc5f61e0712fe25cd45b137773decaf4b9bb582))
|
||||||
|
|
||||||
|
# [2.174.0-dev.19](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.18...v2.174.0-dev.19) (2023-05-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **youtube/video-speed:** change custom video speeds inside app settings ([#2114](https://github.com/revanced/revanced-patches/issues/2114)) ([d97815a](https://github.com/revanced/revanced-patches/commit/d97815af18e645fd0fa087db0174bcc2a771ec72))
|
||||||
|
|
||||||
|
# [2.174.0-dev.18](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.17...v2.174.0-dev.18) (2023-05-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **youtube/theme:** apply custom seekbar color to video thumbnails ([#2085](https://github.com/revanced/revanced-patches/issues/2085)) ([d497027](https://github.com/revanced/revanced-patches/commit/d4970273ad10f62cd9455ef9b847c686147f7dca))
|
||||||
|
|
||||||
|
# [2.174.0-dev.17](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.16...v2.174.0-dev.17) (2023-05-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **youtube/remember-video-quality:** fix default video quality/speed being applied when resuming app. ([#2112](https://github.com/revanced/revanced-patches/issues/2112)) ([f68a41c](https://github.com/revanced/revanced-patches/commit/f68a41ce9f9a78818d3f28b069e70b8c66125f53))
|
||||||
|
|
||||||
|
# [2.174.0-dev.16](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.15...v2.174.0-dev.16) (2023-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* check for opcode type `CONST` ([e5bb63c](https://github.com/revanced/revanced-patches/commit/e5bb63c7ab4427b6116de4a999be306e0f3cf12e))
|
||||||
|
|
||||||
|
# [2.174.0-dev.15](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.14...v2.174.0-dev.15) (2023-05-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **messenger:** add `disable-switching-emoji-to-sticker-in-message-input-field` patch ([#2099](https://github.com/revanced/revanced-patches/issues/2099)) ([ac5532a](https://github.com/revanced/revanced-patches/commit/ac5532a65c353b1964d9b7d990341fc7362e510d))
|
||||||
|
|
||||||
|
# [2.174.0-dev.14](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.13...v2.174.0-dev.14) (2023-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **youtube/hide-player-overlay:** make it toggleable in settings ([#2044](https://github.com/revanced/revanced-patches/issues/2044)) ([f693d55](https://github.com/revanced/revanced-patches/commit/f693d55caf1e0b72bb1f4c39b1eeb59436191e02))
|
||||||
|
|
||||||
# [2.174.0-dev.13](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.12...v2.174.0-dev.13) (2023-05-07)
|
# [2.174.0-dev.13](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.12...v2.174.0-dev.13) (2023-05-07)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
74
README.md
74
README.md
@@ -15,7 +15,6 @@ The official ReVanced Patches.
|
|||||||
| `copy-video-url` | Adds buttons in player to copy video links. | 18.16.37 |
|
| `copy-video-url` | Adds buttons in player to copy video links. | 18.16.37 |
|
||||||
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
|
| `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.16.37 |
|
| `custom-video-buffer` | Lets you change the buffers of videos. | 18.16.37 |
|
||||||
| `custom-video-speed` | Adds more video speed options. | 18.16.37 |
|
|
||||||
| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.16.37 |
|
| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.16.37 |
|
||||||
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.16.37 |
|
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.16.37 |
|
||||||
| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.16.37 |
|
| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.16.37 |
|
||||||
@@ -34,11 +33,12 @@ The official ReVanced Patches.
|
|||||||
| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.16.37 |
|
| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.16.37 |
|
||||||
| `hide-email-address` | Hides the email address in the account switcher. | 18.16.37 |
|
| `hide-email-address` | Hides the email address in the account switcher. | 18.16.37 |
|
||||||
| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.16.37 |
|
| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.16.37 |
|
||||||
|
| `hide-filter-bar` | Hides the filter bar in video feeds. | 18.16.37 |
|
||||||
| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.16.37 |
|
| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.16.37 |
|
||||||
| `hide-get-premium` | Hides advertisement for YouTube Premium under the video player. | 18.16.37 |
|
| `hide-get-premium` | Hides advertisement for YouTube Premium under the video player. | 18.16.37 |
|
||||||
| `hide-info-cards` | Hides info cards in videos. | 18.16.37 |
|
| `hide-info-cards` | Hides info cards in videos. | 18.16.37 |
|
||||||
| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | all |
|
| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | all |
|
||||||
| `hide-player-overlay` | Hides the dark player overlay when player controls are visible. | all |
|
| `hide-player-overlay` | Hides the dark background overlay from the player when player controls are visible. | all |
|
||||||
| `hide-seekbar` | Hides the seekbar. | 18.16.37 |
|
| `hide-seekbar` | Hides the seekbar. | 18.16.37 |
|
||||||
| `hide-timestamp` | Hides timestamp in video player. | 18.16.37 |
|
| `hide-timestamp` | Hides timestamp in video player. | 18.16.37 |
|
||||||
| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.16.37 |
|
| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.16.37 |
|
||||||
@@ -49,7 +49,6 @@ The official ReVanced Patches.
|
|||||||
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.16.37 |
|
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.16.37 |
|
||||||
| `open-links-externally` | Open links outside of the app directly in your browser. | 18.16.37 |
|
| `open-links-externally` | Open links outside of the app directly in your browser. | 18.16.37 |
|
||||||
| `premium-heading` | Shows premium branding on the home screen. | all |
|
| `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.16.37 |
|
|
||||||
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.16.37 |
|
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.16.37 |
|
||||||
| `remove-player-button-background` | Removes the background from the video player buttons. | 18.16.37 |
|
| `remove-player-button-background` | Removes the background from the video player buttons. | 18.16.37 |
|
||||||
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.16.37 |
|
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.16.37 |
|
||||||
@@ -58,7 +57,6 @@ The official ReVanced Patches.
|
|||||||
| `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.16.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.16.37 |
|
||||||
| `swipe-controls` | Adds volume and brightness swipe controls. | 18.16.37 |
|
| `swipe-controls` | Adds volume and brightness swipe controls. | 18.16.37 |
|
||||||
| `tablet-mini-player` | Enables the tablet mini player layout. | 18.16.37 |
|
| `tablet-mini-player` | Enables the tablet mini player layout. | 18.16.37 |
|
||||||
| `theme` | Applies a custom theme. | all |
|
|
||||||
| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.16.37 |
|
| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.16.37 |
|
||||||
| `video-ads` | Removes ads in the video player. | 18.16.37 |
|
| `video-ads` | Removes ads in the video player. | 18.16.37 |
|
||||||
| `wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.16.37 |
|
| `wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.16.37 |
|
||||||
@@ -119,6 +117,7 @@ The official ReVanced Patches.
|
|||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `auto-claim-channel-points` | Automatically claim channel points. | all |
|
||||||
| `block-audio-ads` | Blocks audio ads in streams and VODs. | 14.6.1 |
|
| `block-audio-ads` | Blocks audio ads in streams and VODs. | 14.6.1 |
|
||||||
| `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 14.6.1 |
|
| `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 14.6.1 |
|
||||||
| `block-video-ads` | Blocks video ads in streams and VODs. | 14.6.1 |
|
| `block-video-ads` | Blocks video ads in streams and VODs. | 14.6.1 |
|
||||||
@@ -158,6 +157,15 @@ The official ReVanced Patches.
|
|||||||
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
|
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### [📦 `com.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca)
|
||||||
|
<details>
|
||||||
|
|
||||||
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `disable-switching-emoji-to-sticker-in-message-input-field` | Disables switching from emoji to sticker search mode in message input field | all |
|
||||||
|
| `hide-inbox-ads` | Hides ads in inbox. | all |
|
||||||
|
</details>
|
||||||
|
|
||||||
### [📦 `at.gv.bmf.bmf2go`](https://play.google.com/store/apps/details?id=at.gv.bmf.bmf2go)
|
### [📦 `at.gv.bmf.bmf2go`](https://play.google.com/store/apps/details?id=at.gv.bmf.bmf2go)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
@@ -216,14 +224,6 @@ The official ReVanced Patches.
|
|||||||
| `hide-ads` | Removes general ads. | all |
|
| `hide-ads` | Removes general ads. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### [📦 `com.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca)
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `hide-inbox-ads` | Hides ads in inbox. | all |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### [📦 `com.instagram.android`](https://play.google.com/store/apps/details?id=com.instagram.android)
|
### [📦 `com.instagram.android`](https://play.google.com/store/apps/details?id=com.instagram.android)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
@@ -312,30 +312,6 @@ The official ReVanced Patches.
|
|||||||
| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all |
|
| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `unlock-pro` | Unlocks all pro features. | all |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `unlock-pro` | Unlocks all professional features. | 3.4.9 |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
|
|
||||||
<details>
|
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|
||||||
| `unlock-pro` | Unlocks pro features. | 4.6377 |
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
|
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
@@ -344,6 +320,14 @@ The official ReVanced Patches.
|
|||||||
| `unlock-pro` | Unlocks pro features. | all |
|
| `unlock-pro` | Unlocks pro features. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
|
||||||
|
<details>
|
||||||
|
|
||||||
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `unlock-pro` | Unlocks all pro features. | all |
|
||||||
|
</details>
|
||||||
|
|
||||||
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
|
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
@@ -352,7 +336,7 @@ The official ReVanced Patches.
|
|||||||
| `unlock-pro` | Unlocks all pro features. | all |
|
| `unlock-pro` | Unlocks all pro features. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
|
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
@@ -360,6 +344,22 @@ The official ReVanced Patches.
|
|||||||
| `unlock-pro` | Unlocks all pro features. | all |
|
| `unlock-pro` | Unlocks all pro features. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
|
||||||
|
<details>
|
||||||
|
|
||||||
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `unlock-pro` | Unlocks pro features. | 4.6377 |
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
|
||||||
|
<details>
|
||||||
|
|
||||||
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `unlock-pro` | Unlocks all professional features. | 3.4.9 |
|
||||||
|
</details>
|
||||||
|
|
||||||
### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task)
|
### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 2.174.0-dev.13
|
version = 2.174.0-dev.23
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
|
|||||||
|
package app.revanced.patches.messenger.inputfield.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
object SwitchMessangeInputEmojiButtonFingerprint : MethodFingerprint(
|
||||||
|
returnType = "V",
|
||||||
|
parameters = listOf("L", "Z"),
|
||||||
|
strings = listOf("afterTextChanged", "expression_search"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_STRING,
|
||||||
|
Opcode.GOTO
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package app.revanced.patches.messenger.inputfield.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.toErrorResult
|
||||||
|
import app.revanced.patcher.annotation.*
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.instruction
|
||||||
|
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.inputfield.fingerprints.SwitchMessangeInputEmojiButtonFingerprint
|
||||||
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("disable-switching-emoji-to-sticker-in-message-input-field")
|
||||||
|
@Description("Disables switching from emoji to sticker search mode in message input field")
|
||||||
|
@Compatibility([Package("com.facebook.orca")])
|
||||||
|
@Version("0.0.1")
|
||||||
|
class DisableSwitchingEmojiToStickerInMessageInputField : BytecodePatch(listOf(SwitchMessangeInputEmojiButtonFingerprint)) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
SwitchMessangeInputEmojiButtonFingerprint.result?.let {
|
||||||
|
val setStringIndex = it.scanResult.patternScanResult!!.startIndex + 2
|
||||||
|
|
||||||
|
it.mutableMethod.apply {
|
||||||
|
val targetRegister = instruction<OneRegisterInstruction>(setStringIndex).registerA
|
||||||
|
|
||||||
|
replaceInstruction(
|
||||||
|
setStringIndex,
|
||||||
|
"const-string v$targetRegister, \"expression\""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: throw SwitchMessangeInputEmojiButtonFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package app.revanced.patches.shared.settings.preference.impl
|
package app.revanced.patches.shared.settings.preference.impl
|
||||||
|
|
||||||
enum class InputType(val type: String) {
|
enum class InputType(val type: String) {
|
||||||
STRING("text"),
|
STRING("text"), // TODO: rename to "TEXT"
|
||||||
|
TEXT_CAP_CHARACTERS("textCapCharacters"),
|
||||||
|
TEXT_MULTI_LINE("textMultiLine"),
|
||||||
NUMBER("number"),
|
NUMBER("number"),
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package app.revanced.patches.twitch.chat.autoclaim.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility([Package("tv.twitch.android.app")])
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
internal annotation class AutoClaimChannelPointsCompatibility
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package app.revanced.patches.twitch.chat.autoclaim.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
object CommunityPointsButtonViewDelegateFingerprint : MethodFingerprint(
|
||||||
|
customFingerprint = { methodDef ->
|
||||||
|
methodDef.definingClass.endsWith("CommunityPointsButtonViewDelegate;")
|
||||||
|
&& methodDef.name == "showClaimAvailable"
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package app.revanced.patches.twitch.chat.autoclaim.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.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
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
|
import app.revanced.patches.twitch.chat.autoclaim.annotations.AutoClaimChannelPointsCompatibility
|
||||||
|
import app.revanced.patches.twitch.chat.autoclaim.fingerprints.CommunityPointsButtonViewDelegateFingerprint
|
||||||
|
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@DependsOn([SettingsPatch::class])
|
||||||
|
@Name("auto-claim-channel-points")
|
||||||
|
@Description("Automatically claim channel points.")
|
||||||
|
@AutoClaimChannelPointsCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class AutoClaimChannelPointPatch : BytecodePatch(
|
||||||
|
listOf(CommunityPointsButtonViewDelegateFingerprint)
|
||||||
|
) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences(
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_auto_claim_channel_points",
|
||||||
|
StringResource(
|
||||||
|
"revanced_auto_claim_channel_points",
|
||||||
|
"Automatically claim channel points"
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
StringResource(
|
||||||
|
"revanced_auto_claim_channel_points_on",
|
||||||
|
"Channel points are claimed automatically"
|
||||||
|
),
|
||||||
|
StringResource(
|
||||||
|
"revanced_auto_claim_channel_points_off",
|
||||||
|
"Channel points are not claimed automatically"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
CommunityPointsButtonViewDelegateFingerprint.result?.mutableMethod?.apply {
|
||||||
|
val lastIndex = implementation!!.instructions.lastIndex
|
||||||
|
addInstructions(
|
||||||
|
lastIndex, // place in front of return-void
|
||||||
|
"""
|
||||||
|
invoke-static {}, Lapp/revanced/twitch/patches/AutoClaimChannelPointsPatch;->shouldAutoClaim()Z
|
||||||
|
move-result v0
|
||||||
|
if-eqz v0, :auto_claim
|
||||||
|
|
||||||
|
# Claim by calling the button's onClick method
|
||||||
|
|
||||||
|
iget-object v0, p0, Ltv/twitch/android/shared/community/points/viewdelegate/CommunityPointsButtonViewDelegate;->buttonLayout:Landroid/view/ViewGroup;
|
||||||
|
invoke-virtual { v0 }, Landroid/view/View;->callOnClick()Z
|
||||||
|
""",
|
||||||
|
listOf(ExternalLabel("auto_claim", instruction(lastIndex)))
|
||||||
|
)
|
||||||
|
} ?: return CommunityPointsButtonViewDelegateFingerprint.toErrorResult()
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ import app.revanced.patcher.patch.annotations.Patch
|
|||||||
import app.revanced.patches.youtube.interaction.copyvideourl.annotation.CopyVideoUrlCompatibility
|
import app.revanced.patches.youtube.interaction.copyvideourl.annotation.CopyVideoUrlCompatibility
|
||||||
import app.revanced.patches.youtube.interaction.copyvideourl.resource.patch.CopyVideoUrlResourcePatch
|
import app.revanced.patches.youtube.interaction.copyvideourl.resource.patch.CopyVideoUrlResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("copy-video-url")
|
@Name("copy-video-url")
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import app.revanced.patcher.patch.annotations.Patch
|
|||||||
import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility
|
import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility
|
||||||
import app.revanced.patches.youtube.interaction.downloads.resource.patch.DownloadsResourcePatch
|
import app.revanced.patches.youtube.interaction.downloads.resource.patch.DownloadsResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("downloads")
|
@Name("downloads")
|
||||||
|
|||||||
@@ -12,16 +12,12 @@ import app.revanced.patcher.patch.annotations.Patch
|
|||||||
import app.revanced.patches.youtube.layout.buttons.player.background.annotations.PlayerButtonBackgroundCompatibility
|
import app.revanced.patches.youtube.layout.buttons.player.background.annotations.PlayerButtonBackgroundCompatibility
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
@Patch
|
@Patch(false)
|
||||||
@Name("remove-player-button-background")
|
@Name("remove-player-button-background")
|
||||||
@Description("Removes the background from the video player buttons.")
|
@Description("Removes the background from the video player buttons.")
|
||||||
@PlayerButtonBackgroundCompatibility
|
@PlayerButtonBackgroundCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class PlayerButtonBackgroundPatch : ResourcePatch {
|
class PlayerButtonBackgroundPatch : ResourcePatch {
|
||||||
private companion object {
|
|
||||||
const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun execute(context: ResourceContext): PatchResult {
|
override fun execute(context: ResourceContext): PatchResult {
|
||||||
context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
|
context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
|
||||||
editor.file.doRecursively node@{ node ->
|
editor.file.doRecursively node@{ node ->
|
||||||
@@ -35,4 +31,8 @@ class PlayerButtonBackgroundPatch : ResourcePatch {
|
|||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37"))])
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
internal annotation class HideFilterBar
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.filterBarHeightId
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
object FilterBarHeightFingerprint : LiteralOpcodesFingerprint(
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IPUT
|
||||||
|
),
|
||||||
|
filterBarHeightId
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
|
||||||
|
|
||||||
|
abstract class LiteralOpcodesFingerprint(opcodes: List<Opcode>, literal: Long) : MethodFingerprint(
|
||||||
|
opcodes = opcodes,
|
||||||
|
customFingerprint = {
|
||||||
|
it.implementation?.instructions?.any { instruction ->
|
||||||
|
if (instruction.opcode != Opcode.CONST) return@any false
|
||||||
|
|
||||||
|
val wideLiteral = (instruction as WideLiteralInstruction).wideLiteral
|
||||||
|
|
||||||
|
literal == wideLiteral
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.relatedChipCloudMarginId
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
object RelatedChipCloudFingerprint : LiteralOpcodesFingerprint(
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT
|
||||||
|
),
|
||||||
|
relatedChipCloudMarginId
|
||||||
|
)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.barContainerHeightId
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
object SearchResultsChipBarFingerprint : LiteralOpcodesFingerprint(
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT
|
||||||
|
),
|
||||||
|
barContainerHeightId
|
||||||
|
)
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.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.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.instruction
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.annotations.HideFilterBar
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.FilterBarHeightFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.RelatedChipCloudFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.SearchResultsChipBarFingerprint
|
||||||
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("hide-filter-bar")
|
||||||
|
@Description("Hides the filter bar in video feeds.")
|
||||||
|
@DependsOn([HideFilterBarResourcePatch::class])
|
||||||
|
@HideFilterBar
|
||||||
|
@Version("0.0.1")
|
||||||
|
class HideFilterBarPatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
RelatedChipCloudFingerprint,
|
||||||
|
SearchResultsChipBarFingerprint,
|
||||||
|
FilterBarHeightFingerprint
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
FilterBarHeightFingerprint.patch<TwoRegisterInstruction> { register ->
|
||||||
|
"""
|
||||||
|
invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->hideInFeed(I)I
|
||||||
|
move-result v$register
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
RelatedChipCloudFingerprint.patch<OneRegisterInstruction>(1) { register ->
|
||||||
|
"invoke-static { v$register }, " +
|
||||||
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideInRelatedVideos(Landroid/view/View;)V"
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchResultsChipBarFingerprint.patch<OneRegisterInstruction>(-1, -2) { register ->
|
||||||
|
"""
|
||||||
|
invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->hideInSearch(I)I
|
||||||
|
move-result v$register
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
|
"Lapp/revanced/integrations/patches/HideFilterBarPatch;"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch a [MethodFingerprint] with a given [instructions].
|
||||||
|
*
|
||||||
|
* @param RegisterInstruction The type of instruction to get the register from.
|
||||||
|
* @param insertIndexOffset The offset to add to the end index of the [MethodFingerprint].
|
||||||
|
* @param hookRegisterOffset The offset to add to the register of the hook.
|
||||||
|
* @param instructions The instructions to add with the register as a parameter.
|
||||||
|
*/
|
||||||
|
private fun <RegisterInstruction: OneRegisterInstruction> MethodFingerprint.patch(
|
||||||
|
insertIndexOffset: Int = 0,
|
||||||
|
hookRegisterOffset: Int = 0,
|
||||||
|
instructions: (Int) -> String
|
||||||
|
) =
|
||||||
|
result?.let {
|
||||||
|
it.mutableMethod.apply {
|
||||||
|
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
|
||||||
|
val insertIndex = endIndex + insertIndexOffset
|
||||||
|
val register = instruction<RegisterInstruction>(endIndex + hookRegisterOffset).registerA
|
||||||
|
|
||||||
|
addInstructions(insertIndex, instructions(register))
|
||||||
|
}
|
||||||
|
} ?: throw toErrorResult()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.filterbar.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.ResourceContext
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
|
||||||
|
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||||
|
@Version("0.0.1")
|
||||||
|
class HideFilterBarResourcePatch : ResourcePatch {
|
||||||
|
override fun execute(context: ResourceContext): PatchResult {
|
||||||
|
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||||
|
PreferenceScreen(
|
||||||
|
"revanced_hide_filter_bar_preference",
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_preference_title",
|
||||||
|
"Hide filter bar"
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_hide_filter_bar_feed_in_feed",
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_feed_title",
|
||||||
|
"Hide in feed"
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_feed_summary_on",
|
||||||
|
"Hidden in feed"
|
||||||
|
),
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_feed_summary_off",
|
||||||
|
"Shown in feed"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_hide_filter_bar_feed_in_search",
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_search_title",
|
||||||
|
"Hide in search"
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_search_summary_on",
|
||||||
|
"Hidden in search"
|
||||||
|
),
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_search_summary_off",
|
||||||
|
"Shown in search"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_hide_filter_bar_feed_in_related_videos",
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_related_videos_title",
|
||||||
|
"Hide in related videos"
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_related_videos_summary_on",
|
||||||
|
"Hidden in related videos"
|
||||||
|
),
|
||||||
|
StringResource(
|
||||||
|
"revanced_hide_filter_bar_feed_in_related_videos_summary_off",
|
||||||
|
"Shown in related videos"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
relatedChipCloudMarginId = "related_chip_cloud_reduced_margins".layoutResourceId("layout")
|
||||||
|
filterBarHeightId = "filter_bar_height".layoutResourceId()
|
||||||
|
barContainerHeightId = "bar_container_height".layoutResourceId()
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal companion object {
|
||||||
|
var filterBarHeightId = -1L
|
||||||
|
var relatedChipCloudMarginId = -1L
|
||||||
|
var barContainerHeightId = -1L
|
||||||
|
|
||||||
|
private fun String.layoutResourceId(type: String = "dimen") =
|
||||||
|
ResourceMappingPatch.resourceMappings.single { it.type == type && it.name == this }.id
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.player.overlay.bytecode.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch.HidePlayerOverlayResourcePatch
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
|
||||||
|
object CreatePlayerOverviewFingerprint : MethodFingerprint(
|
||||||
|
returnType = "V",
|
||||||
|
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CHECK_CAST
|
||||||
|
),
|
||||||
|
customFingerprint = { methodDef ->
|
||||||
|
methodDef.implementation?.instructions?.any {
|
||||||
|
if (it.opcode != Opcode.CONST) return@any false
|
||||||
|
|
||||||
|
val literal = (it as WideLiteralInstruction).wideLiteral
|
||||||
|
|
||||||
|
literal == HidePlayerOverlayResourcePatch.scrimOverlayId
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.player.overlay.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
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.addInstruction
|
||||||
|
import app.revanced.patcher.extensions.instruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patches.youtube.layout.hide.player.overlay.annotations.HidePlayerOverlayPatchCompatibility
|
||||||
|
import app.revanced.patches.youtube.layout.hide.player.overlay.bytecode.fingerprints.CreatePlayerOverviewFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch.HidePlayerOverlayResourcePatch
|
||||||
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("hide-player-overlay")
|
||||||
|
@Description("Hides the dark background overlay from the player when player controls are visible.")
|
||||||
|
@DependsOn([HidePlayerOverlayResourcePatch::class])
|
||||||
|
@HidePlayerOverlayPatchCompatibility
|
||||||
|
@Version("0.0.2")
|
||||||
|
class HidePlayerOverlayPatch : BytecodePatch(listOf(CreatePlayerOverviewFingerprint)) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
CreatePlayerOverviewFingerprint.result?.let { result ->
|
||||||
|
result.mutableMethod.apply {
|
||||||
|
val viewRegisterIndex = implementation!!.instructions.indexOfFirst {
|
||||||
|
val literal = (it as? WideLiteralInstruction)?.wideLiteral
|
||||||
|
|
||||||
|
literal == HidePlayerOverlayResourcePatch.scrimOverlayId
|
||||||
|
} + 3
|
||||||
|
val viewRegister = instruction<OneRegisterInstruction>(viewRegisterIndex).registerA
|
||||||
|
|
||||||
|
val insertIndex = viewRegisterIndex + 1
|
||||||
|
addInstruction(
|
||||||
|
insertIndex,
|
||||||
|
"invoke-static { v$viewRegister }, " +
|
||||||
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->hidePlayerOverlay(Landroid/widget/ImageView;)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return CreatePlayerOverviewFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/HidePlayerOverlayPatch;"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.layout.hide.player.overlay.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
|
||||||
import app.revanced.patches.youtube.layout.hide.player.overlay.annotations.HidePlayerOverlayPatchCompatibility
|
|
||||||
|
|
||||||
@Patch(false)
|
|
||||||
@Name("hide-player-overlay")
|
|
||||||
@Description("Hides the dark player overlay when player controls are visible.")
|
|
||||||
@HidePlayerOverlayPatchCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class HidePlayerOverlayPatch : ResourcePatch {
|
|
||||||
override fun execute(context: ResourceContext): PatchResult {
|
|
||||||
val attributes = arrayOf("height", "width")
|
|
||||||
|
|
||||||
context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
|
|
||||||
editor.file.getElementsByTagName("FrameLayout").item(0).childNodes.apply {
|
|
||||||
for (i in 1 until length) {
|
|
||||||
val view = item(i)
|
|
||||||
if (
|
|
||||||
view.attributes.getNamedItem("android:id")
|
|
||||||
?.nodeValue
|
|
||||||
?.endsWith("scrim_overlay") == true
|
|
||||||
) {
|
|
||||||
attributes.forEach {
|
|
||||||
view.attributes.getNamedItem("android:layout_$it").nodeValue = "0.0dip"
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
const val RESOURCE_FILE_PATH = "res/layout/youtube_controls_overlay.xml"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.ResourceContext
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
|
import app.revanced.patches.youtube.layout.hide.player.overlay.annotations.HidePlayerOverlayPatchCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
import jdk.jfr.Name
|
||||||
|
|
||||||
|
@Name("hide-player-overlay-resource-patch")
|
||||||
|
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||||
|
@HidePlayerOverlayPatchCompatibility
|
||||||
|
class HidePlayerOverlayResourcePatch : ResourcePatch {
|
||||||
|
override fun execute(context: ResourceContext): PatchResult {
|
||||||
|
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_hide_player_overlay",
|
||||||
|
StringResource("revanced_hide_player_overlay_title", "Hide background overlay in player"),
|
||||||
|
false,
|
||||||
|
StringResource("revanced_hide_player_overlay_summary_on", "Background overlay is hidden"),
|
||||||
|
StringResource("revanced_hide_player_overlay_summary_off", "Background overlay is shown")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
scrimOverlayId = ResourceMappingPatch.resourceMappings.single {
|
||||||
|
it.type == "id" && it.name == "scrim_overlay"
|
||||||
|
}.id
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal companion object {
|
||||||
|
var scrimOverlayId: Long = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,11 +16,16 @@ import app.revanced.patches.shared.fingerprints.SeekbarOnDrawFingerprint
|
|||||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
import app.revanced.patches.youtube.layout.hide.seekbar.annotations.HideSeekbarCompatibility
|
import app.revanced.patches.youtube.layout.hide.seekbar.annotations.HideSeekbarCompatibility
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.bytecode.patch.SeekbarColorBytecodePatch
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
@DependsOn([
|
||||||
|
IntegrationsPatch::class,
|
||||||
|
SettingsPatch::class,
|
||||||
|
SeekbarColorBytecodePatch::class // Used to hide the seekbar in the feed and watch history
|
||||||
|
])
|
||||||
@Name("hide-seekbar")
|
@Name("hide-seekbar")
|
||||||
@Description("Hides the seekbar.")
|
@Description("Hides the seekbar.")
|
||||||
@HideSeekbarCompatibility
|
@HideSeekbarCompatibility
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.*
|
|||||||
import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
|
||||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.seekbar.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility([Package("com.google.android.youtube")])
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
internal annotation class SeekbarColorCompatibility
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.resource.SeekbarColorResourcePatch
|
||||||
|
import app.revanced.util.patch.indexOfFirstConstantInstruction
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
object CreateDarkThemeSeekbarFingerprint : MethodFingerprint(
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
customFingerprint = { method ->
|
||||||
|
method.indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId) != -1
|
||||||
|
&& method.indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarPlayedNotHighlightedColorId) != -1
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints
|
package app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.seekbar.bytecode.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.data.toMethodWalker
|
||||||
|
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
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.annotations.SeekbarColorCompatibility
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints.SetSeekbarClickedColorFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.theme.bytecode.patch.LithoColorHookPatch
|
||||||
|
import app.revanced.patches.youtube.layout.theme.bytecode.patch.LithoColorHookPatch.Companion.lithoColorOverrideHook
|
||||||
|
import app.revanced.patches.youtube.layout.seekbar.resource.SeekbarColorResourcePatch
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
|
import app.revanced.util.patch.indexOfFirstConstantInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
|
@Description("Hide or set a custom seekbar color")
|
||||||
|
@DependsOn([IntegrationsPatch::class, LithoColorHookPatch::class, SeekbarColorResourcePatch::class])
|
||||||
|
@SeekbarColorCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class SeekbarColorBytecodePatch : BytecodePatch(
|
||||||
|
listOf(CreateDarkThemeSeekbarFingerprint, SetSeekbarClickedColorFingerprint)
|
||||||
|
) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
CreateDarkThemeSeekbarFingerprint.result?.mutableMethod?.apply {
|
||||||
|
var registerIndex = indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId) + 2
|
||||||
|
var colorRegister = (instruction(registerIndex) as OneRegisterInstruction).registerA
|
||||||
|
addInstructions(
|
||||||
|
registerIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue(I)I
|
||||||
|
move-result v$colorRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
registerIndex = indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarPlayedNotHighlightedColorId) + 2
|
||||||
|
colorRegister = (instruction(registerIndex) as OneRegisterInstruction).registerA
|
||||||
|
addInstructions(
|
||||||
|
registerIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue(I)I
|
||||||
|
move-result v$colorRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
} ?: return CreateDarkThemeSeekbarFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
SetSeekbarClickedColorFingerprint.result?.let { result ->
|
||||||
|
result.mutableMethod.let {
|
||||||
|
val setColorMethodIndex = result.scanResult.patternScanResult!!.startIndex + 1
|
||||||
|
val method = context
|
||||||
|
.toMethodWalker(it)
|
||||||
|
.nextMethod(setColorMethodIndex, true)
|
||||||
|
.getMethod() as MutableMethod
|
||||||
|
|
||||||
|
method.apply {
|
||||||
|
val colorRegister = (method.instruction(0) as TwoRegisterInstruction).registerA
|
||||||
|
addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorOverride(I)I
|
||||||
|
move-result v$colorRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} ?: return SetSeekbarClickedColorFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
lithoColorOverrideHook(INTEGRATIONS_CLASS_DESCRIPTOR, "getSeekbarColorOverride")
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/SeekbarColorPatch;"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.seekbar.resource
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.ResourceContext
|
||||||
|
import app.revanced.patcher.patch.*
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||||
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||||
|
class SeekbarColorResourcePatch : ResourcePatch {
|
||||||
|
override fun execute(context: ResourceContext): PatchResult {
|
||||||
|
// Edit theme colors via bytecode.
|
||||||
|
// For that the resource id is used in a bytecode patch to change the color.
|
||||||
|
|
||||||
|
val seekbarErrorMessage = "Could not find seekbar resource"
|
||||||
|
inlineTimeBarColorizedBarPlayedColorDarkId = ResourceMappingPatch.resourceMappings
|
||||||
|
.find { it.name == "inline_time_bar_colorized_bar_played_color_dark" }?.id
|
||||||
|
?: return PatchResultError(seekbarErrorMessage)
|
||||||
|
inlineTimeBarPlayedNotHighlightedColorId = ResourceMappingPatch.resourceMappings
|
||||||
|
.find { it.name == "inline_time_bar_played_not_highlighted_color" }?.id
|
||||||
|
?: return PatchResultError(seekbarErrorMessage)
|
||||||
|
|
||||||
|
// Edit the resume playback drawable and replace the progress bar with a custom drawable
|
||||||
|
context.xmlEditor["res/drawable/resume_playback_progressbar_drawable.xml"].use { editor ->
|
||||||
|
val layerList = editor.file.getElementsByTagName("layer-list").item(0) as Element
|
||||||
|
val progressNode = layerList.getElementsByTagName("item").item(1) as Element
|
||||||
|
if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {
|
||||||
|
return PatchResultError("Could not find progress bar")
|
||||||
|
}
|
||||||
|
val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element
|
||||||
|
val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element
|
||||||
|
val replacementNode = editor.file.createElement(
|
||||||
|
"app.revanced.integrations.patches.theme.ProgressBarDrawable")
|
||||||
|
scaleNode.replaceChild(replacementNode, shapeNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L
|
||||||
|
internal var inlineTimeBarPlayedNotHighlightedColorId = -1L
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,8 +31,8 @@ import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParen
|
|||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
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.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
|
||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.*
|
import org.jf.dexlib2.iface.instruction.*
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint.indexOfInstructionWithSeekbarId
|
|
||||||
import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
import org.jf.dexlib2.iface.Method
|
|
||||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
|
||||||
|
|
||||||
object CreateDarkThemeSeekbarFingerprint : MethodFingerprint(
|
|
||||||
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
|
||||||
customFingerprint = { method -> method.indexOfInstructionWithSeekbarId != -1 },
|
|
||||||
) {
|
|
||||||
/**
|
|
||||||
* The index of the instruction that loads the resource id of the seekbar.
|
|
||||||
*/
|
|
||||||
internal val Method.indexOfInstructionWithSeekbarId
|
|
||||||
get() = implementation?.let {
|
|
||||||
it.instructions.indexOfFirst { instruction ->
|
|
||||||
instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == ThemeResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.layout.theme.fingerprints
|
package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.theme.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
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
||||||
|
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.LithoThemeFingerprint
|
||||||
|
|
||||||
|
@Name("litho-color-hook")
|
||||||
|
@Description("Adds a hook to set color of Litho components.")
|
||||||
|
@ThemeCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class LithoColorHookPatch : BytecodePatch(listOf(LithoThemeFingerprint)) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
LithoThemeFingerprint.result?.let {
|
||||||
|
insertionIndex = it.scanResult.patternScanResult!!.endIndex - 1
|
||||||
|
colorRegister = "p1"
|
||||||
|
insertionMethod = it.mutableMethod
|
||||||
|
} ?: return LithoThemeFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
companion object {
|
||||||
|
private var insertionIndex : Int = -1
|
||||||
|
private lateinit var colorRegister : String
|
||||||
|
private lateinit var insertionMethod : MutableMethod
|
||||||
|
|
||||||
|
internal fun lithoColorOverrideHook(targetMethodClass: String, targetMethodName: String) {
|
||||||
|
insertionMethod.addInstructions(
|
||||||
|
insertionIndex,
|
||||||
|
"""
|
||||||
|
invoke-static {$colorRegister}, $targetMethodClass->$targetMethodName(I)I
|
||||||
|
move-result $colorRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
insertionIndex += 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,76 +1,34 @@
|
|||||||
package app.revanced.patches.youtube.layout.theme.bytecode.patch
|
package app.revanced.patches.youtube.layout.theme.bytecode.patch
|
||||||
|
|
||||||
import app.revanced.extensions.toErrorResult
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.data.toMethodWalker
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.instruction
|
|
||||||
import app.revanced.patcher.patch.*
|
import app.revanced.patcher.patch.*
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patches.youtube.layout.seekbar.bytecode.patch.SeekbarColorBytecodePatch
|
||||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
import app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint
|
||||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint
|
import app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints.SetSeekbarClickedColorFingerprint
|
||||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint.indexOfInstructionWithSeekbarId
|
|
||||||
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.SetSeekbarClickedColorFingerprint
|
|
||||||
import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch
|
import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
|
||||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("theme")
|
@Name("theme")
|
||||||
@Description("Applies a custom theme.")
|
@Description("Applies a custom theme.")
|
||||||
@DependsOn([ThemeLithoComponentsPatch::class, ThemeResourcePatch::class, IntegrationsPatch::class])
|
@DependsOn([LithoColorHookPatch::class, SeekbarColorBytecodePatch::class, ThemeResourcePatch::class])
|
||||||
@ThemeCompatibility
|
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class ThemeBytecodePatch : BytecodePatch(
|
class ThemeBytecodePatch : BytecodePatch(
|
||||||
listOf(CreateDarkThemeSeekbarFingerprint, SetSeekbarClickedColorFingerprint)
|
listOf(CreateDarkThemeSeekbarFingerprint, SetSeekbarClickedColorFingerprint)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
CreateDarkThemeSeekbarFingerprint.result?.let {
|
LithoColorHookPatch.lithoColorOverrideHook(INTEGRATIONS_CLASS_DESCRIPTOR, "getValue")
|
||||||
val putColorValueIndex = it.method.indexOfInstructionWithSeekbarId!! + 3
|
|
||||||
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val overrideRegister = instruction<TwoRegisterInstruction>(putColorValueIndex).registerA
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
putColorValueIndex,
|
|
||||||
"""
|
|
||||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue()I
|
|
||||||
move-result v$overrideRegister
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: return CreateDarkThemeSeekbarFingerprint.toErrorResult()
|
|
||||||
|
|
||||||
SetSeekbarClickedColorFingerprint.result?.let { result ->
|
|
||||||
result.mutableMethod.let {
|
|
||||||
val setColorMethodIndex = result.scanResult.patternScanResult!!.startIndex + 1
|
|
||||||
val method = context
|
|
||||||
.toMethodWalker(it)
|
|
||||||
.nextMethod(setColorMethodIndex, true)
|
|
||||||
.getMethod() as MutableMethod
|
|
||||||
|
|
||||||
method.apply {
|
|
||||||
val colorRegister = method.instruction<TwoRegisterInstruction>(0).registerA
|
|
||||||
addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarClickedColorValue(I)I
|
|
||||||
move-result v$colorRegister
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: return SetSeekbarClickedColorFingerprint.toErrorResult()
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : OptionsContainer() {
|
companion object : OptionsContainer() {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemePatch;"
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemeLithoComponentsPatch;"
|
||||||
|
|
||||||
var darkThemeBackgroundColor: String? by option(
|
var darkThemeBackgroundColor: String? by option(
|
||||||
PatchOption.StringOption(
|
PatchOption.StringOption(
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.layout.theme.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
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
|
|
||||||
import app.revanced.patches.youtube.layout.theme.fingerprints.LithoThemeFingerprint
|
|
||||||
|
|
||||||
@Name("theme-litho-components")
|
|
||||||
@Description("Applies a custom theme to Litho components.")
|
|
||||||
@ThemeCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class ThemeLithoComponentsPatch : BytecodePatch(listOf(LithoThemeFingerprint)) {
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
|
||||||
LithoThemeFingerprint.result?.let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val patchIndex = it.scanResult.patternScanResult!!.endIndex - 1
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
patchIndex,
|
|
||||||
"""
|
|
||||||
invoke-static {p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->getValue(I)I
|
|
||||||
move-result p1
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: return LithoThemeFingerprint.toErrorResult()
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemeLithoComponentsPatch;"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
package app.revanced.patches.youtube.layout.theme.resource
|
package app.revanced.patches.youtube.layout.theme.resource
|
||||||
|
|
||||||
import app.revanced.patcher.data.ResourceContext
|
import app.revanced.patcher.data.ResourceContext
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.*
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
|
||||||
import app.revanced.patches.shared.settings.preference.impl.InputType
|
import app.revanced.patches.shared.settings.preference.impl.InputType
|
||||||
@@ -28,19 +25,11 @@ class ThemeResourcePatch : ResourcePatch {
|
|||||||
"#FF0000",
|
"#FF0000",
|
||||||
StringResource(
|
StringResource(
|
||||||
"revanced_seekbar_color_summary",
|
"revanced_seekbar_color_summary",
|
||||||
"The color of the seekbar for the dark theme."
|
"The color of the seekbar"
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Edit theme colors via bytecode.
|
|
||||||
// For that the resource id is used in a bytecode patch to change the color.
|
|
||||||
|
|
||||||
inlineTimeBarColorizedBarPlayedColorDarkId = ResourceMappingPatch.resourceMappings
|
|
||||||
.find { it.name == "inline_time_bar_colorized_bar_played_color_dark" }?.id
|
|
||||||
?: return PatchResultError("Could not find seekbar resource")
|
|
||||||
|
|
||||||
|
|
||||||
val darkThemeBackgroundColor = darkThemeBackgroundColor!!
|
val darkThemeBackgroundColor = darkThemeBackgroundColor!!
|
||||||
val lightThemeBackgroundColor = lightThemeBackgroundColor!!
|
val lightThemeBackgroundColor = lightThemeBackgroundColor!!
|
||||||
|
|
||||||
@@ -72,7 +61,4 @@ class ThemeResourcePatch : ResourcePatch {
|
|||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal companion object {
|
|
||||||
var inlineTimeBarColorizedBarPlayedColorDarkId = -1L
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SubtitleWindo
|
|||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Name("spoof-signature-verification")
|
@Name("spoof-signature-verification")
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ class SettingsPatch : BytecodePatch(
|
|||||||
val ADS = Screen("ads", "Ads", "Ad related settings")
|
val ADS = Screen("ads", "Ads", "Ad related settings")
|
||||||
val INTERACTIONS = Screen("interactions", "Interaction", "Settings related to interactions")
|
val INTERACTIONS = Screen("interactions", "Interaction", "Settings related to interactions")
|
||||||
val LAYOUT = Screen("layout", "Layout", "Settings related to the layout")
|
val LAYOUT = Screen("layout", "Layout", "Settings related to the layout")
|
||||||
|
val VIDEO = Screen("video", "Video", "Settings related to the video player")
|
||||||
val MISC = Screen("misc", "Misc", "Miscellaneous patches")
|
val MISC = Screen("misc", "Misc", "Miscellaneous patches")
|
||||||
|
|
||||||
override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) {
|
override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
object VideoSpeedPatchFingerprint : MethodFingerprint(
|
|
||||||
opcodes = listOf(Opcode.FILL_ARRAY_DATA),
|
|
||||||
customFingerprint = { methodDef ->
|
|
||||||
methodDef.definingClass.endsWith("CustomVideoSpeedPatch;") && methodDef.name == "<clinit>"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.custom.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.extensions.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 org.jf.dexlib2.builder.instruction.BuilderArrayPayload
|
|
||||||
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
|
||||||
import java.util.stream.DoubleStream
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("custom-video-speed")
|
|
||||||
@Description("Adds more video speed options.")
|
|
||||||
@DependsOn([IntegrationsPatch::class])
|
|
||||||
@CustomPlaybackSpeedCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class CustomVideoSpeedPatch : BytecodePatch(
|
|
||||||
listOf(
|
|
||||||
SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint, VideoSpeedPatchFingerprint
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
|
||||||
val speedLimitMin = minVideoSpeed!!.toFloat()
|
|
||||||
val speedLimitMax = maxVideoSpeed!!.toFloat().coerceAtLeast(speedLimitMin)
|
|
||||||
val speedsGranularity = videoSpeedsGranularity!!.toFloat()
|
|
||||||
|
|
||||||
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
|
|
||||||
val arrayGenMethodImpl = arrayGenMethod.implementation!!
|
|
||||||
|
|
||||||
val sizeCallIndex = arrayGenMethodImpl.instructions
|
|
||||||
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
|
|
||||||
|
|
||||||
if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()")
|
|
||||||
|
|
||||||
val sizeCallResultRegister =
|
|
||||||
(arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
arrayGenMethod.replaceInstruction(
|
|
||||||
sizeCallIndex + 1,
|
|
||||||
"const/4 v$sizeCallResultRegister, 0x0"
|
|
||||||
)
|
|
||||||
|
|
||||||
val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex()
|
|
||||||
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
|
|
||||||
|
|
||||||
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->videoSpeeds:[F"
|
|
||||||
|
|
||||||
arrayGenMethod.addInstructions(
|
|
||||||
arrayLengthConstIndex + 1,
|
|
||||||
"""
|
|
||||||
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
|
|
||||||
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex()
|
|
||||||
.first {
|
|
||||||
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
|
|
||||||
reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
|
|
||||||
reference?.type == "[F"
|
|
||||||
}
|
|
||||||
|
|
||||||
val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
arrayGenMethod.replaceInstruction(
|
|
||||||
originalArrayFetchIndex,
|
|
||||||
"sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType"
|
|
||||||
)
|
|
||||||
|
|
||||||
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!
|
|
||||||
val limiterMethodImpl = limiterMethod.implementation!!
|
|
||||||
|
|
||||||
val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex()
|
|
||||||
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
|
|
||||||
val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex()
|
|
||||||
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
|
|
||||||
|
|
||||||
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
|
|
||||||
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
|
|
||||||
|
|
||||||
limiterMethod.replaceInstruction(
|
|
||||||
limiterMinConstIndex,
|
|
||||||
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
|
|
||||||
)
|
|
||||||
limiterMethod.replaceInstruction(
|
|
||||||
limiterMaxConstIndex,
|
|
||||||
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
val constructorResult = VideoSpeedPatchFingerprint.result!!
|
|
||||||
val constructor = constructorResult.mutableMethod
|
|
||||||
val implementation = constructor.implementation!!
|
|
||||||
|
|
||||||
val stepsGranularity = 8F
|
|
||||||
val step = speedLimitMax
|
|
||||||
.minus(speedLimitMin) // calculate the range of the speeds
|
|
||||||
.div(speedsGranularity)
|
|
||||||
.times(stepsGranularity)
|
|
||||||
.roundToInt()
|
|
||||||
.div(stepsGranularity)// round to nearest multiple of stepsGranularity
|
|
||||||
.coerceAtLeast(1 / stepsGranularity) // ensure steps are at least 1/8th of the step granularity
|
|
||||||
|
|
||||||
val videoSpeedsArray = buildList<Number> {
|
|
||||||
DoubleStream
|
|
||||||
.iterate(speedLimitMin.toDouble()) { it + step } // create a stream of speeds
|
|
||||||
.let { speedStream ->
|
|
||||||
for (speed in speedStream) {
|
|
||||||
if (speed > speedLimitMax) break
|
|
||||||
add(speed.toFloat().toRawBits())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust the new array of speeds size
|
|
||||||
constructor.replaceInstruction(
|
|
||||||
0,
|
|
||||||
"const/16 v0, ${videoSpeedsArray.size}"
|
|
||||||
)
|
|
||||||
|
|
||||||
// create the payload with the new speeds
|
|
||||||
val arrayPayloadIndex = implementation.instructions.size - 1
|
|
||||||
implementation.replaceInstruction(
|
|
||||||
arrayPayloadIndex,
|
|
||||||
BuilderArrayPayload(
|
|
||||||
4,
|
|
||||||
videoSpeedsArray
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : OptionsContainer() {
|
|
||||||
private fun String?.validate(max: Int? = null) = this?.toFloatOrNull() != null &&
|
|
||||||
toFloat().let { float ->
|
|
||||||
float > 0 && max?.let { max -> float <= max } ?: true
|
|
||||||
}
|
|
||||||
|
|
||||||
val videoSpeedsGranularity by option(
|
|
||||||
PatchOption.StringOption(
|
|
||||||
"granularity",
|
|
||||||
"16",
|
|
||||||
"Video speed granularity",
|
|
||||||
"The granularity of the video speeds. The higher the value, the more speeds will be available.",
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
it.validate()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val minVideoSpeed by option(
|
|
||||||
PatchOption.StringOption(
|
|
||||||
"min",
|
|
||||||
"0.25",
|
|
||||||
"Minimum video speed",
|
|
||||||
"The minimum video speed.",
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
it.validate()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val maxVideoSpeed by option(
|
|
||||||
PatchOption.StringOption(
|
|
||||||
"max",
|
|
||||||
"5.0",
|
|
||||||
"Maximum video speed",
|
|
||||||
"The maximum video speed. Must be greater than the minimum video speed and smaller than 5.",
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
it.validate(5)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.hdrbrightness.annotations
|
package app.revanced.patches.youtube.video.hdrbrightness.annotations
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.hdrbrightness.fingerprints
|
package app.revanced.patches.youtube.video.hdrbrightness.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.hdrbrightness.patch
|
package app.revanced.patches.youtube.video.hdrbrightness.patch
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
@@ -10,8 +10,8 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patches.youtube.misc.hdrbrightness.annotations.HDRBrightnessCompatibility
|
import app.revanced.patches.youtube.video.hdrbrightness.annotations.HDRBrightnessCompatibility
|
||||||
import app.revanced.patches.youtube.misc.hdrbrightness.fingerprints.HDRBrightnessFingerprint
|
import app.revanced.patches.youtube.video.hdrbrightness.fingerprints.HDRBrightnessFingerprint
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
@@ -30,7 +30,7 @@ class HDRBrightnessPatch : BytecodePatch(
|
|||||||
listOf(HDRBrightnessFingerprint)
|
listOf(HDRBrightnessFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_pref_hdr_autobrightness",
|
"revanced_pref_hdr_autobrightness",
|
||||||
StringResource("revanced_hdr_autobrightness_enabled_title", "Enable auto HDR brightness"),
|
StringResource("revanced_hdr_autobrightness_enabled_title", "Enable auto HDR brightness"),
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.annotation
|
package app.revanced.patches.youtube.video.information.annotation
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.fingerprints
|
package app.revanced.patches.youtube.video.information.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.information.patch
|
package app.revanced.patches.youtube.video.information.patch
|
||||||
|
|
||||||
import app.revanced.extensions.toErrorResult
|
import app.revanced.extensions.toErrorResult
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
@@ -19,10 +19,10 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
|||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility
|
import app.revanced.patches.youtube.video.information.annotation.VideoInformationCompatibility
|
||||||
import app.revanced.patches.youtube.misc.video.information.fingerprints.*
|
import app.revanced.patches.youtube.video.information.fingerprints.*
|
||||||
import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.BuilderInstruction
|
import org.jf.dexlib2.builder.BuilderInstruction
|
||||||
@@ -54,7 +54,7 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
||||||
|
|
||||||
// hook the player controller for use through integrations
|
// hook the player controller for use through integrations
|
||||||
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "playerController_onCreateHook")
|
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
||||||
|
|
||||||
// seek method
|
// seek method
|
||||||
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method
|
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method
|
||||||
@@ -160,24 +160,32 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/VideoInformation;"
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/VideoInformation;"
|
||||||
|
|
||||||
private lateinit var playerInitMethod: MutableMethod
|
private lateinit var playerInitMethod: MutableMethod
|
||||||
|
private var playerInitInsertIndex = 4
|
||||||
|
|
||||||
private lateinit var timeMethod: MutableMethod
|
private lateinit var timeMethod: MutableMethod
|
||||||
|
private var timeInitInsertIndex = 2
|
||||||
|
|
||||||
private lateinit var highPrecisionTimeMethod: MutableMethod
|
private lateinit var highPrecisionTimeMethod: MutableMethod
|
||||||
|
private var highPrecisionInsertIndex = 0
|
||||||
|
|
||||||
private fun MutableMethod.insert(insert: InsertIndex, register: String, descriptor: String) =
|
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||||
addInstruction(insert.index, "invoke-static { $register }, $descriptor")
|
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||||
|
|
||||||
private fun MutableMethod.insertTimeHook(insert: InsertIndex, descriptor: String) =
|
private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) =
|
||||||
insert(insert, "p1, p2", descriptor)
|
insert(insertIndex, "p1, p2", descriptor)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook the player controller.
|
* Hook the player controller. Called when a video is opened or the current video is changed.
|
||||||
|
*
|
||||||
|
* Note: This hook is called very early and is called before the video id, video time, video length,
|
||||||
|
* and many other data fields are set.
|
||||||
*
|
*
|
||||||
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
||||||
* @param targetMethodName The name of 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.
|
||||||
*/
|
*/
|
||||||
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
|
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
|
||||||
playerInitMethod.insert(
|
playerInitMethod.insert(
|
||||||
InsertIndex.CREATE,
|
playerInitInsertIndex++,
|
||||||
"v0",
|
"v0",
|
||||||
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||||
)
|
)
|
||||||
@@ -191,7 +199,7 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
*/
|
*/
|
||||||
internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||||
timeMethod.insertTimeHook(
|
timeMethod.insertTimeHook(
|
||||||
InsertIndex.TIME,
|
timeInitInsertIndex++,
|
||||||
"$targetMethodClass->$targetMethodName(J)V"
|
"$targetMethodClass->$targetMethodName(J)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -205,16 +213,10 @@ class VideoInformationPatch : BytecodePatch(
|
|||||||
*/
|
*/
|
||||||
internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) =
|
internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||||
highPrecisionTimeMethod.insertTimeHook(
|
highPrecisionTimeMethod.insertTimeHook(
|
||||||
InsertIndex.HIGH_PRECISION_TIME,
|
highPrecisionInsertIndex++,
|
||||||
"$targetMethodClass->$targetMethodName(J)V"
|
"$targetMethodClass->$targetMethodName(J)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class InsertIndex(internal val index: Int) {
|
|
||||||
CREATE(4),
|
|
||||||
TIME(2),
|
|
||||||
HIGH_PRECISION_TIME(0),
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) =
|
private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) =
|
||||||
instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference
|
instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.layout.oldqualitylayout.annotations
|
package app.revanced.patches.youtube.video.oldqualitylayout.annotations
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints
|
package app.revanced.patches.youtube.video.oldqualitylayout.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.layout.oldqualitylayout.patch
|
package app.revanced.patches.youtube.video.oldqualitylayout.patch
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
@@ -10,12 +10,12 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
|
|
||||||
import app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint
|
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
|
||||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
|
import app.revanced.patches.youtube.video.oldqualitylayout.annotations.OldQualityLayoutCompatibility
|
||||||
|
import app.revanced.patches.youtube.video.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint
|
||||||
|
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.FiveRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@@ -30,7 +30,7 @@ class OldQualityLayoutPatch : BytecodePatch(
|
|||||||
listOf(QualityMenuViewInflateFingerprint)
|
listOf(QualityMenuViewInflateFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
|
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_use_old_style_quality_settings",
|
"revanced_use_old_style_quality_settings",
|
||||||
StringResource("revanced_old_style_quality_settings_enabled_title", "Use old video quality player menu"),
|
StringResource("revanced_old_style_quality_settings_enabled_title", "Use old video quality player menu"),
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.quality.annotations
|
package app.revanced.patches.youtube.video.quality.annotations
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.quality.fingerprints
|
package app.revanced.patches.youtube.video.quality.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
package app.revanced.patches.youtube.misc.video.quality.fingerprints
|
package app.revanced.patches.youtube.video.quality.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
package app.revanced.patches.youtube.misc.video.quality.fingerprints
|
package app.revanced.patches.youtube.video.quality.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.quality.patch
|
package app.revanced.patches.youtube.video.quality.patch
|
||||||
|
|
||||||
import app.revanced.extensions.toErrorResult
|
import app.revanced.extensions.toErrorResult
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
@@ -20,16 +20,16 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource
|
|||||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
import app.revanced.patches.youtube.misc.video.quality.annotations.RememberVideoQualityCompatibility
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.misc.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint
|
import app.revanced.patches.youtube.video.quality.annotations.RememberVideoQualityCompatibility
|
||||||
import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint
|
import app.revanced.patches.youtube.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint
|
||||||
import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualitySetterFingerprint
|
import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySetterFingerprint
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@DependsOn([IntegrationsPatch::class, VideoIdPatch::class, SettingsPatch::class])
|
@DependsOn([IntegrationsPatch::class, VideoInformationPatch::class, SettingsPatch::class])
|
||||||
@Name("remember-video-quality")
|
@Name("remember-video-quality")
|
||||||
@Description("Adds the ability to remember the video quality you chose in the video quality flyout.")
|
@Description("Adds the ability to remember the video quality you chose in the video quality flyout.")
|
||||||
@RememberVideoQualityCompatibility
|
@RememberVideoQualityCompatibility
|
||||||
@@ -41,25 +41,6 @@ class RememberVideoQualityPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
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"
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
StringResource(
|
|
||||||
"revanced_remember_video_quality_last_selected_summary_on",
|
|
||||||
"Quality changes apply to all videos"
|
|
||||||
),
|
|
||||||
StringResource(
|
|
||||||
"revanced_remember_video_quality_last_selected_summary_off",
|
|
||||||
"Quality changes only apply to the current video"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is bloated as each value has it's own String key/value
|
// 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)
|
// ideally the entries would be raw values (and not a key to a String resource)
|
||||||
val entries = listOf(
|
val entries = listOf(
|
||||||
@@ -84,7 +65,24 @@ class RememberVideoQualityPatch : BytecodePatch(
|
|||||||
StringResource("revanced_default_quality_entry_value_8", "280"),
|
StringResource("revanced_default_quality_entry_value_8", "280"),
|
||||||
StringResource("revanced_default_quality_entry_value_9", "144"),
|
StringResource("revanced_default_quality_entry_value_9", "144"),
|
||||||
)
|
)
|
||||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
|
||||||
|
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_remember_video_quality_last_selected",
|
||||||
|
StringResource(
|
||||||
|
"revanced_remember_video_quality_last_selected_title",
|
||||||
|
"Remember video quality changes"
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
StringResource(
|
||||||
|
"revanced_remember_video_quality_last_selected_summary_on",
|
||||||
|
"Quality changes apply to all videos"
|
||||||
|
),
|
||||||
|
StringResource(
|
||||||
|
"revanced_remember_video_quality_last_selected_summary_off",
|
||||||
|
"Quality changes only apply to the current video"
|
||||||
|
)
|
||||||
|
),
|
||||||
ListPreference(
|
ListPreference(
|
||||||
"revanced_default_video_quality_wifi",
|
"revanced_default_video_quality_wifi",
|
||||||
StringResource(
|
StringResource(
|
||||||
@@ -114,7 +112,7 @@ class RememberVideoQualityPatch : BytecodePatch(
|
|||||||
* Conveniently, at this point the video quality is overridden to the remembered playback speed.
|
* Conveniently, at this point the video quality is overridden to the remembered playback speed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
VideoIdPatch.injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted")
|
||||||
|
|
||||||
// Inject a call to set the remembered quality once a video loads.
|
// Inject a call to set the remembered quality once a video loads.
|
||||||
VideoQualitySetterFingerprint.result?.also {
|
VideoQualitySetterFingerprint.result?.also {
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package app.revanced.patches.youtube.video.speed
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patches.youtube.video.speed.custom.patch.CustomVideoSpeedPatch
|
||||||
|
import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("video-speed")
|
||||||
|
@Description("Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.")
|
||||||
|
@DependsOn([CustomVideoSpeedPatch::class, RememberPlaybackSpeedPatch::class])
|
||||||
|
@Version("0.0.1")
|
||||||
|
class VideoSpeeds : BytecodePatch() {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
return PatchResultSuccess() // All patches this patch depends on succeed.
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.custom.annotations
|
package app.revanced.patches.youtube.video.speed.custom.annotations
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints
|
package app.revanced.patches.youtube.video.speed.custom.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints
|
package app.revanced.patches.youtube.video.speed.custom.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package app.revanced.patches.youtube.video.speed.custom.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.patch.*
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.InputType
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||||
|
import app.revanced.patches.shared.settings.preference.impl.TextPreference
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
import app.revanced.patches.youtube.video.speed.custom.annotations.CustomPlaybackSpeedCompatibility
|
||||||
|
import app.revanced.patches.youtube.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint
|
||||||
|
import app.revanced.patches.youtube.video.speed.custom.fingerprints.SpeedLimiterFingerprint
|
||||||
|
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
@Name("custom-video-speed")
|
||||||
|
@Description("Adds custom video speed options.")
|
||||||
|
@DependsOn([IntegrationsPatch::class])
|
||||||
|
@CustomPlaybackSpeedCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
|
||||||
|
TextPreference(
|
||||||
|
key = "revanced_custom_video_speeds",
|
||||||
|
title = StringResource(
|
||||||
|
"revanced_custom_video_speeds_title",
|
||||||
|
"Custom playback speeds"
|
||||||
|
),
|
||||||
|
inputType = InputType.TEXT_MULTI_LINE,
|
||||||
|
summary = StringResource(
|
||||||
|
"revanced_custom_video_speeds_summary",
|
||||||
|
"Add or change the video speeds available"
|
||||||
|
),
|
||||||
|
default = "0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
|
||||||
|
val arrayGenMethodImpl = arrayGenMethod.implementation!!
|
||||||
|
|
||||||
|
val sizeCallIndex = arrayGenMethodImpl.instructions
|
||||||
|
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
|
||||||
|
|
||||||
|
if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()")
|
||||||
|
|
||||||
|
val sizeCallResultRegister =
|
||||||
|
(arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
|
arrayGenMethod.replaceInstruction(
|
||||||
|
sizeCallIndex + 1,
|
||||||
|
"const/4 v$sizeCallResultRegister, 0x0"
|
||||||
|
)
|
||||||
|
|
||||||
|
val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex()
|
||||||
|
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
|
||||||
|
|
||||||
|
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
|
val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->customVideoSpeeds:[F"
|
||||||
|
|
||||||
|
arrayGenMethod.addInstructions(
|
||||||
|
arrayLengthConstIndex + 1,
|
||||||
|
"""
|
||||||
|
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
|
||||||
|
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex()
|
||||||
|
.first {
|
||||||
|
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
|
||||||
|
reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
|
||||||
|
reference?.type == "[F"
|
||||||
|
}
|
||||||
|
|
||||||
|
val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
|
arrayGenMethod.replaceInstruction(
|
||||||
|
originalArrayFetchIndex,
|
||||||
|
"sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType"
|
||||||
|
)
|
||||||
|
|
||||||
|
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!
|
||||||
|
val limiterMethodImpl = limiterMethod.implementation!!
|
||||||
|
|
||||||
|
val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex()
|
||||||
|
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
|
||||||
|
val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex()
|
||||||
|
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
|
||||||
|
|
||||||
|
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
|
||||||
|
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
|
// edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x
|
||||||
|
limiterMethod.replaceInstruction(
|
||||||
|
limiterMinConstIndex,
|
||||||
|
"sget v$limiterMinConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->minVideoSpeed:F"
|
||||||
|
)
|
||||||
|
limiterMethod.replaceInstruction(
|
||||||
|
limiterMaxConstIndex,
|
||||||
|
"sget v$limiterMaxConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->maxVideoSpeed:F"
|
||||||
|
)
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.remember.annotation
|
package app.revanced.patches.youtube.video.speed.remember.annotation
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
|
package app.revanced.patches.youtube.video.speed.remember.fingerprint
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.speed.remember.patch
|
package app.revanced.patches.youtube.video.speed.remember.patch
|
||||||
|
|
||||||
import app.revanced.extensions.toErrorResult
|
import app.revanced.extensions.toErrorResult
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
@@ -19,16 +19,15 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource
|
|||||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch.Companion.reference
|
||||||
import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
|
import app.revanced.patches.youtube.video.speed.custom.patch.CustomVideoSpeedPatch
|
||||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
|
import app.revanced.patches.youtube.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
import app.revanced.patches.youtube.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
|
||||||
|
|
||||||
@Patch
|
|
||||||
@Name("remember-playback-speed")
|
@Name("remember-playback-speed")
|
||||||
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
|
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
|
||||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class, VideoInformationPatch::class])
|
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomVideoSpeedPatch::class])
|
||||||
@RememberPlaybackSpeedCompatibility
|
@RememberPlaybackSpeedCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RememberPlaybackSpeedPatch : BytecodePatch(
|
class RememberPlaybackSpeedPatch : BytecodePatch(
|
||||||
@@ -37,7 +36,7 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
SettingsPatch.PreferenceScreen.VIDEO.addPreferences(
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
"revanced_remember_playback_speed_last_selected",
|
"revanced_remember_playback_speed_last_selected",
|
||||||
StringResource(
|
StringResource(
|
||||||
@@ -53,10 +52,7 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
"revanced_remember_playback_speed_last_selected_summary_off",
|
"revanced_remember_playback_speed_last_selected_summary_off",
|
||||||
"Playback speed changes only apply to the current video"
|
"Playback speed changes only apply to the current video"
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
)
|
|
||||||
|
|
||||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
|
||||||
ListPreference(
|
ListPreference(
|
||||||
"revanced_default_playback_speed",
|
"revanced_default_playback_speed",
|
||||||
StringResource(
|
StringResource(
|
||||||
@@ -77,8 +73,7 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V")
|
VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted")
|
||||||
|
|
||||||
VideoInformationPatch.userSelectedPlaybackSpeedHook(
|
VideoInformationPatch.userSelectedPlaybackSpeedHook(
|
||||||
INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
|
INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")
|
||||||
|
|
||||||
@@ -124,4 +119,4 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
|
|||||||
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
|
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.videoid.annotation
|
package app.revanced.patches.youtube.video.videoid.annotation
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.videoid.fingerprint
|
package app.revanced.patches.youtube.video.videoid.fingerprint
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.videoid.fingerprint
|
package app.revanced.patches.youtube.video.videoid.fingerprint
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.misc.video.videoid.patch
|
package app.revanced.patches.youtube.video.videoid.patch
|
||||||
|
|
||||||
import app.revanced.extensions.toErrorResult
|
import app.revanced.extensions.toErrorResult
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
@@ -13,9 +13,9 @@ import app.revanced.patcher.patch.PatchResultSuccess
|
|||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.annotation.VideoIdCompatibility
|
import app.revanced.patches.youtube.video.videoid.annotation.VideoIdCompatibility
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprint
|
import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprint
|
||||||
import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay
|
import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Name("video-id-hook")
|
@Name("video-id-hook")
|
||||||
16
src/main/kotlin/app/revanced/util/patch/BytecodeUtils.kt
Normal file
16
src/main/kotlin/app/revanced/util/patch/BytecodeUtils.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package app.revanced.util.patch
|
||||||
|
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the first constant instruction with the resource id, or -1 if not found.
|
||||||
|
*/
|
||||||
|
fun Method.indexOfFirstConstantInstruction(constantValue: Long): Int {
|
||||||
|
return implementation?.let {
|
||||||
|
it.instructions.indexOfFirst { instruction ->
|
||||||
|
instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == constantValue
|
||||||
|
}
|
||||||
|
} ?: -1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user