Compare commits

...

48 Commits

Author SHA1 Message Date
semantic-release-bot
48965ace7e chore(release): 2.174.0-dev.19 [skip ci]
# [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)) ([08f1702](08f1702b18))
2023-05-11 06:27:32 +00:00
LisoUseInAIKyrios
08f1702b18 feat(youtube/video-speed): change custom video speeds inside app settings (#2114) 2023-05-11 10:25:21 +04:00
semantic-release-bot
45784eceee chore(release): 2.174.0-dev.18 [skip ci]
# [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)) ([f891aa9](f891aa937c))
2023-05-11 06:24:29 +00:00
LisoUseInAIKyrios
f891aa937c fix(youtube/theme): apply custom seekbar color to video thumbnails (#2085) 2023-05-11 10:22:37 +04:00
LisoUseInAIKyrios
aa493c4f67 chore: fix merge 2023-05-09 21:08:12 +04:00
semantic-release-bot
a83e0dc257 chore(release): 2.174.0-dev.17 [skip ci]
# [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)) ([5ea4d3c](5ea4d3c2a6))
2023-05-09 15:53:20 +00:00
LisoUseInAIKyrios
5ea4d3c2a6 fix(youtube/remember-video-quality): fix default video quality/speed being applied when resuming app. (#2112) 2023-05-09 19:51:13 +04:00
oSumAtrIX
f4ae7fd9d7 build: use Java SDK 17 for building 2023-05-09 07:13:14 +02:00
semantic-release-bot
b6539922fe chore(release): 2.174.0-dev.16 [skip ci]
# [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` ([a697b16](a697b16aa3))
2023-05-08 23:45:47 +00:00
oSumAtrIX
a697b16aa3 fix: check for opcode type CONST 2023-05-09 01:44:00 +02:00
semantic-release-bot
ab22794ef2 chore(release): 2.174.0-dev.15 [skip ci]
# [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)) ([cd6988a](cd6988a688))
2023-05-08 00:10:59 +00:00
badawoll
cd6988a688 feat(messenger): add disable-switching-emoji-to-sticker-in-message-input-field patch (#2099)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-05-08 02:08:27 +02:00
semantic-release-bot
74ad4fa5ea chore(release): 2.174.0-dev.14 [skip ci]
# [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)) ([382c441](382c441de5))
2023-05-07 23:59:26 +00:00
johnconner122
382c441de5 feat(youtube/hide-player-overlay): make it toggleable in settings (#2044)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-05-08 01:57:44 +02:00
semantic-release-bot
7953a1a07b chore(release): 2.174.0-dev.13 [skip ci]
# [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)

### Bug Fixes

* account fo breaking changes from ReVanced Patcher ([#2103](https://github.com/revanced/revanced-patches/issues/2103)) ([ac0ed24](ac0ed24ef2))
2023-05-07 23:50:12 +00:00
rstular
ac0ed24ef2 fix: account fo breaking changes from ReVanced Patcher (#2103)
RE: revanced/revanced-patcher/commit/6f6434fdb191fa4150d07ef1ec829fe570b3c664
2023-05-08 01:47:32 +02:00
semantic-release-bot
489663c890 chore(release): 2.174.0-dev.12 [skip ci]
# [2.174.0-dev.12](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.11...v2.174.0-dev.12) (2023-05-07)

### Bug Fixes

* **readme-generator:** attempt sorting versions with `FlexVer` ([#2059](https://github.com/revanced/revanced-patches/issues/2059)) ([599e089](599e089c12))
2023-05-07 23:46:21 +00:00
rstular
599e089c12 fix(readme-generator): attempt sorting versions with FlexVer (#2059)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-05-08 01:43:06 +02:00
semantic-release-bot
0d54b73958 chore(release): 2.174.0-dev.11 [skip ci]
# [2.174.0-dev.11](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.10...v2.174.0-dev.11) (2023-05-07)
2023-05-07 23:25:50 +00:00
oSumAtrIX
943f6de55b build: downgrade to JDK version 11 2023-05-08 01:15:26 +02:00
oSumAtrIX
7649e54c22 build(revanced-patcher): bump version 2023-05-08 01:15:07 +02:00
oSumAtrIX
671c822fe9 refactor: reduce variable initializer 2023-05-08 01:14:08 +02:00
semantic-release-bot
56727bbe68 chore(release): 2.174.0-dev.10 [skip ci]
# [2.174.0-dev.10](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.9...v2.174.0-dev.10) (2023-05-07)

### Bug Fixes

* incorrect instruction offsets ([5ff5d80](5ff5d804e2))
* incorrect smali syntax ([9ca1f85](9ca1f853e0))
2023-05-07 17:00:12 +00:00
oSumAtrIX
5ff5d804e2 fix: incorrect instruction offsets 2023-05-07 18:58:10 +02:00
oSumAtrIX
9ca1f853e0 fix: incorrect smali syntax 2023-05-07 18:58:09 +02:00
semantic-release-bot
d229095087 chore(release): 2.174.0-dev.9 [skip ci]
# [2.174.0-dev.9](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.8...v2.174.0-dev.9) (2023-05-07)

### Bug Fixes

* incorrect cast of instruction ([bc38b9e](bc38b9ebc2))
2023-05-07 16:35:35 +00:00
oSumAtrIX
bc38b9ebc2 fix: incorrect cast of instruction 2023-05-07 18:34:00 +02:00
semantic-release-bot
3d79d5b7f0 chore(release): 2.174.0-dev.8 [skip ci]
# [2.174.0-dev.8](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.7...v2.174.0-dev.8) (2023-05-07)

### Bug Fixes

* **youtube/integrations:** allow playback of embedded videos  ([#2092](https://github.com/revanced/revanced-patches/issues/2092)) ([b2de406](b2de406844))
2023-05-07 16:29:14 +00:00
LisoUseInAIKyrios
b2de406844 fix(youtube/integrations): allow playback of embedded videos (#2092)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-05-07 20:27:35 +04:00
semantic-release-bot
35cd7780d0 chore(release): 2.174.0-dev.7 [skip ci]
# [2.174.0-dev.7](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.6...v2.174.0-dev.7) (2023-05-07)

### Features

* **syncforreddit:** add `disable-ads` patch ([#2066](https://github.com/revanced/revanced-patches/issues/2066)) ([6951e4a](6951e4a0e9))
2023-05-07 16:17:11 +00:00
nik2143
6951e4a0e9 feat(syncforreddit): add disable-ads patch (#2066)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-05-07 18:15:30 +02:00
semantic-release-bot
9bfcf99a22 chore(release): 2.174.0-dev.6 [skip ci]
# [2.174.0-dev.6](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.5...v2.174.0-dev.6) (2023-05-07)

### Features

* **youtube:** `hide-load-more-button` patch ([#2078](https://github.com/revanced/revanced-patches/issues/2078)) ([56d3cf2](56d3cf258c))
2023-05-07 15:28:43 +00:00
johnconner122
56d3cf258c feat(youtube): hide-load-more-button patch (#2078)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-05-07 17:26:58 +02:00
semantic-release-bot
81a5d37bc3 chore(release): 2.174.0-dev.5 [skip ci]
# [2.174.0-dev.5](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.4...v2.174.0-dev.5) (2023-05-07)

### Bug Fixes

* **spotify/disable-capture-restriction:** make compatible with latest versions ([#2095](https://github.com/revanced/revanced-patches/issues/2095)) ([c50f703](c50f703551))
2023-05-07 14:13:32 +00:00
Tim Schneeberger
c50f703551 fix(spotify/disable-capture-restriction): make compatible with latest versions (#2095) 2023-05-07 16:11:52 +02:00
oSumAtrIX
85516401be docs: remove invalid key from example patches.json in README file 2023-05-07 02:42:40 +02:00
oSumAtrIX
311f5d80fc docs: add missing header to README file 2023-05-07 02:33:38 +02:00
semantic-release-bot
73c86c85c6 chore(release): 2.174.0-dev.4 [skip ci]
# [2.174.0-dev.4](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.3...v2.174.0-dev.4) (2023-05-07)

### Bug Fixes

* **youtube/theme:** move options out of dependency patch ([9727cfc](9727cfc169))

### Features

* improve structure of `README` ([751d74f](751d74f5c0))
2023-05-07 00:18:50 +00:00
oSumAtrIX
9727cfc169 fix(youtube/theme): move options out of dependency patch 2023-05-07 02:16:37 +02:00
oSumAtrIX
751d74f5c0 feat: improve structure of README 2023-05-07 02:15:28 +02:00
semantic-release-bot
fe72363c52 chore(release): 2.174.0-dev.3 [skip ci]
# [2.174.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.2...v2.174.0-dev.3) (2023-05-06)
2023-05-06 21:25:17 +00:00
oSumAtrIX
d763108110 ci: release when bumping ReVanced Patcher
This is required when two projects bump ReVanced Patcher, but one does not release a new version, resulting them to get out of sync. For that reason, commits of type `build` and scope `revanced-patcher` are treated as releasing commits.
2023-05-06 23:22:49 +02:00
oSumAtrIX
0af514d76c refactor: simplify casting instructions 2023-05-06 23:22:48 +02:00
oSumAtrIX
6a1cc85439 build(revanced-patcher): bump version 2023-05-06 23:22:47 +02:00
semantic-release-bot
6587acb2c5 chore(release): 2.174.0-dev.2 [skip ci]
# [2.174.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.1...v2.174.0-dev.2) (2023-05-03)

### Features

* **patch:** bump compatibility ([#2060](https://github.com/revanced/revanced-patches/issues/2060)) ([00f6343](00f63439ac))
2023-05-03 08:58:36 +00:00
badawoll
00f63439ac feat(patch): bump compatibility (#2060) 2023-05-03 10:56:28 +02:00
semantic-release-bot
a783834de7 chore(release): 2.174.0-dev.1 [skip ci]
# [2.174.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.173.1-dev.1...v2.174.0-dev.1) (2023-05-03)

### Features

* **youtube/settings:** add reset button to edit preference dialog ([#2047](https://github.com/revanced/revanced-patches/issues/2047)) ([a33d04f](a33d04fdac))
2023-05-03 07:52:53 +00:00
LisoUseInAIKyrios
a33d04fdac feat(youtube/settings): add reset button to edit preference dialog (#2047) 2023-05-03 11:50:35 +04:00
84 changed files with 1244 additions and 628 deletions

View File

@@ -7,7 +7,13 @@
}
],
"plugins": [
"@semantic-release/commit-analyzer",
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "revanced-patcher", "release": "patch" }
]
}
],
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"gradle-semantic-release-plugin",

View File

@@ -1,3 +1,132 @@
# [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)
### Bug Fixes
* account fo breaking changes from ReVanced Patcher ([#2103](https://github.com/revanced/revanced-patches/issues/2103)) ([5be25cd](https://github.com/revanced/revanced-patches/commit/5be25cde4b34d58ced35a7edbb499477b538b748))
# [2.174.0-dev.12](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.11...v2.174.0-dev.12) (2023-05-07)
### Bug Fixes
* **readme-generator:** attempt sorting versions with `FlexVer` ([#2059](https://github.com/revanced/revanced-patches/issues/2059)) ([a54c464](https://github.com/revanced/revanced-patches/commit/a54c464522fa2a6a2d2525c8cb0ec961c2cc771c))
# [2.174.0-dev.11](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.10...v2.174.0-dev.11) (2023-05-07)
# [2.174.0-dev.10](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.9...v2.174.0-dev.10) (2023-05-07)
### Bug Fixes
* incorrect instruction offsets ([42a5a38](https://github.com/revanced/revanced-patches/commit/42a5a387da3c53c579234a44c124ab0ba26117cb))
* incorrect smali syntax ([4e74a80](https://github.com/revanced/revanced-patches/commit/4e74a800c311d7acb2c2ddb492b43747db8a8def))
# [2.174.0-dev.9](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.8...v2.174.0-dev.9) (2023-05-07)
### Bug Fixes
* incorrect cast of instruction ([fb94a1c](https://github.com/revanced/revanced-patches/commit/fb94a1cb48e8952981e2f9146eb90ee92a517b2e))
# [2.174.0-dev.8](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.7...v2.174.0-dev.8) (2023-05-07)
### Bug Fixes
* **youtube/integrations:** allow playback of embedded videos ([#2092](https://github.com/revanced/revanced-patches/issues/2092)) ([8a43d75](https://github.com/revanced/revanced-patches/commit/8a43d75e2db63c47bb9ad1b75027df0868c094e5))
# [2.174.0-dev.7](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.6...v2.174.0-dev.7) (2023-05-07)
### Features
* **syncforreddit:** add `disable-ads` patch ([#2066](https://github.com/revanced/revanced-patches/issues/2066)) ([c1de5d6](https://github.com/revanced/revanced-patches/commit/c1de5d6e433263b9a17305fa1c65807921594731))
# [2.174.0-dev.6](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.5...v2.174.0-dev.6) (2023-05-07)
### Features
* **youtube:** `hide-load-more-button` patch ([#2078](https://github.com/revanced/revanced-patches/issues/2078)) ([7170802](https://github.com/revanced/revanced-patches/commit/71708022a06453f6f56c19d686fc505286523391))
# [2.174.0-dev.5](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.4...v2.174.0-dev.5) (2023-05-07)
### Bug Fixes
* **spotify/disable-capture-restriction:** make compatible with latest versions ([#2095](https://github.com/revanced/revanced-patches/issues/2095)) ([e48f127](https://github.com/revanced/revanced-patches/commit/e48f1278da2a9d82e70be41fa2c4c480c574816b))
# [2.174.0-dev.4](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.3...v2.174.0-dev.4) (2023-05-07)
### Bug Fixes
* **youtube/theme:** move options out of dependency patch ([a953448](https://github.com/revanced/revanced-patches/commit/a95344879c2ac2cd6da8ce0273dcb05e8a35d2ec))
### Features
* improve structure of `README` ([279b193](https://github.com/revanced/revanced-patches/commit/279b193b687ad9cba44ab9c2a88d2ce06be0bbf0))
# [2.174.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.2...v2.174.0-dev.3) (2023-05-06)
# [2.174.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.1...v2.174.0-dev.2) (2023-05-03)
### Features
* **patch:** bump compatibility ([#2060](https://github.com/revanced/revanced-patches/issues/2060)) ([f86836d](https://github.com/revanced/revanced-patches/commit/f86836d6295db9eb8c59916deaa991b4d99e96be))
# [2.174.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.173.1-dev.1...v2.174.0-dev.1) (2023-05-03)
### Features
* **youtube/settings:** add reset button to edit preference dialog ([#2047](https://github.com/revanced/revanced-patches/issues/2047)) ([ede765a](https://github.com/revanced/revanced-patches/commit/ede765ae3c506909ee8a99517b99b6f5f113f01a))
## [2.173.1-dev.1](https://github.com/revanced/revanced-patches/compare/v2.173.0...v2.173.1-dev.1) (2023-05-03)

View File

@@ -1,11 +1,13 @@
## 🧩 Patches
## 🧩 ReVanced Patches
The official Patch bundle provided by ReVanced and the community.
The official ReVanced Patches.
> Looking for the JSON variant of this? [Click here](patches.json).
## 📋 List of patches in this repository
{{ table }}
> Looking for the JSON variant of this? [Click here](patches.json).
## 📝 JSON Format
This section explains the JSON format for the [patches.json](patches.json) file.
@@ -64,7 +66,6 @@ Example:
"description": "Enables a custom theme.",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "theme",
@@ -91,7 +92,6 @@ Example:
"description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "appName",

View File

@@ -1,8 +1,8 @@
## 🧩 Patches
## 🧩 ReVanced Patches
The official Patch bundle provided by ReVanced and the community.
The official ReVanced Patches.
> Looking for the JSON variant of this? [Click here](patches.json).
## 📋 List of patches in this repository
### [📦 `com.google.android.youtube`](https://play.google.com/store/apps/details?id=com.google.android.youtube)
<details>
@@ -15,7 +15,6 @@ The official Patch bundle provided by ReVanced and the community.
| `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-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-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 |
@@ -38,7 +37,7 @@ The official Patch bundle provided by ReVanced and the community.
| `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-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-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 |
@@ -49,7 +48,6 @@ The official Patch bundle provided by ReVanced and the community.
| `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 |
| `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 |
| `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 |
@@ -58,7 +56,6 @@ The official Patch bundle provided by ReVanced and the community.
| `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 |
| `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 |
| `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 |
@@ -158,6 +155,15 @@ The official Patch bundle provided by ReVanced and the community.
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
</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)
<details>
@@ -176,6 +182,14 @@ The official Patch bundle provided by ReVanced and the community.
| `spoof-signature` | Spoofs the signature of the app. | all |
</details>
### [📦 `com.laurencedawson.reddit_sync`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-ads` | Disables ads. | all |
</details>
### [📦 `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit)
<details>
@@ -208,14 +222,6 @@ The official Patch bundle provided by ReVanced and the community.
| `hide-ads` | Removes general ads. | all |
</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)
<details>
@@ -285,7 +291,7 @@ The official Patch bundle provided by ReVanced and the community.
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-plus` | Unlocks plus features. | 8.9.0 |
| `unlock-plus` | Unlocks plus features. | all |
</details>
### [📦 `io.yuka.android`](https://play.google.com/store/apps/details?id=io.yuka.android)
@@ -304,30 +310,6 @@ The official Patch bundle provided by ReVanced and the community.
| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all |
</details>
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all professional features. | 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.6364 |
</details>
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
<details>
@@ -336,6 +318,14 @@ The official Patch bundle provided by ReVanced and the community.
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
<details>
@@ -344,7 +334,7 @@ The official Patch bundle provided by ReVanced and the community.
| `unlock-pro` | Unlocks all pro features. | all |
</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>
| 💊 Patch | 📜 Description | 🏹 Target Version |
@@ -352,6 +342,22 @@ The official Patch bundle provided by ReVanced and the community.
| `unlock-pro` | Unlocks all pro features. | all |
</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)
<details>
@@ -370,6 +376,8 @@ The official Patch bundle provided by ReVanced and the community.
> Looking for the JSON variant of this? [Click here](patches.json).
## 📝 JSON Format
This section explains the JSON format for the [patches.json](patches.json) file.
@@ -428,7 +436,6 @@ Example:
"description": "Enables a custom theme.",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "theme",
@@ -455,7 +462,6 @@ Example:
"description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "appName",

View File

@@ -17,13 +17,26 @@ repositories {
password = githubPassword
}
}
// Required for FlexVer-Java
maven {
url = uri("https://repo.sleeping.town")
content {
includeGroup("com.unascribed")
}
}
}
dependencies {
implementation("app.revanced:revanced-patcher:7.0.0")
implementation("app.revanced:revanced-patcher:7.1.1")
implementation("app.revanced:multidexlib2:2.5.3-a3836654")
// Required for meta
implementation("com.google.code.gson:gson:2.10.1")
// Required for FlexVer-Java
implementation("com.unascribed:flexver-java:1.0.2")
}
kotlin {
jvmToolchain(11)
}
tasks {

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official
version = 2.173.1-dev.1
version = 2.174.0-dev.19

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch
import com.unascribed.flexver.FlexVerComparator
import java.io.File
internal class ReadmeGenerator : PatchesFileGenerator {
@@ -37,9 +38,8 @@ internal class ReadmeGenerator : PatchesFileGenerator {
}
}.let { commonMap ->
commonMap.maxByOrNull { it.value }?.value?.let {
// This is not foolproof, because for example v1.0.0-dev.0 will be returned instead of v1.0.0-release.
// Unfortunately this can not be solved easily because versioning can be complex.
commonMap.entries.filter { mostCommon -> mostCommon.value == it }.maxBy { it.key }.key
commonMap.entries.filter { mostCommon -> mostCommon.value == it }
.maxOfWith(FlexVerComparator::compare, Map.Entry<String, Int>::key)
} ?: "all"
}

View File

@@ -19,7 +19,7 @@ class ChangePackageNamePatch : ResourcePatch {
if (!packageName.matches(packageNameRegex))
return PatchResultError("Invalid package name")
var originalPackageName = ""
var originalPackageName: String
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
originalPackageName = manifest.getAttribute("package")

View File

@@ -1,15 +1,14 @@
package app.revanced.patches.backdrops.misc.pro.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.backdrops.misc.pro.annotations.ProUnlockCompatibility
@@ -25,17 +24,20 @@ class ProUnlockPatch : BytecodePatch(
listOf(ProUnlockFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = ProUnlockFingerprint.result ?: return PatchResultError("${ProUnlockFingerprint.name} not found")
ProUnlockFingerprint.result?.let { result ->
val registerIndex = result.scanResult.patternScanResult!!.endIndex - 1
val moveRegisterInstruction = result.mutableMethod.instruction(result.scanResult.patternScanResult!!.endIndex - 1)
val register = (moveRegisterInstruction as OneRegisterInstruction).registerA
result.mutableMethod.apply {
val register = instruction<OneRegisterInstruction>(registerIndex).registerA
addInstructions(
result.scanResult.patternScanResult!!.endIndex,
"""
const/4 v$register, 0x1
"""
)
}
result.mutableMethod.addInstructions(
result.scanResult.patternScanResult!!.endIndex,
"""
const/4 v$register, 0x1
"""
)
} ?: return ProUnlockFingerprint.toErrorResult()
return PatchResultSuccess()
}

View File

@@ -55,8 +55,8 @@ class HideTimelineAdsPatch : BytecodePatch(
val scanStart = scanResult.patternScanResult!!.startIndex
val jumpIndex = scanStart - 1
val mediaInstanceRegister = (mutableMethod.instruction(scanStart) as FiveRegisterInstruction).registerC
val freeRegister = (mutableMethod.instruction(jumpIndex) as OneRegisterInstruction).registerA
val mediaInstanceRegister = mutableMethod.instruction<FiveRegisterInstruction>(scanStart).registerC
val freeRegister = mutableMethod.instruction<OneRegisterInstruction>(jumpIndex).registerA
val returnFalseLabel = "an_ad"

View File

@@ -3,6 +3,15 @@ package app.revanced.patches.memegenerator.misc.pro.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.zombodroid.MemeGenerator", arrayOf("4.6364"))])
@Compatibility(
[Package(
"com.zombodroid.MemeGenerator", arrayOf(
"4.6364",
"4.6370",
"4.6375",
"4.6377",
)
)]
)
@Target(AnnotationTarget.CLASS)
internal annotation class UnlockProCompatibility

View File

@@ -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
)
)

View File

@@ -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()
}
}

View File

@@ -1,30 +0,0 @@
package app.revanced.patches.photomath.misc.unlockplus.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.microblink.photomath", arrayOf(
"8.6.0",
"8.7.0",
"8.8.0",
"8.9.0",
"8.10.0",
"8.11.0",
"8.12.0",
"8.13.0",
"8.14.0",
"8.15.0",
"8.16.0",
"8.17.0",
"8.18.0",
"8.18.1",
"8.19.0",
"8.20.0",
"8.21.0",
)
)]
)
@Target(AnnotationTarget.CLASS)
internal annotation class UnlockPlusCompatibilty

View File

@@ -1,8 +1,10 @@
package app.revanced.patches.photomath.misc.unlockplus.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Package
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
@@ -12,14 +14,13 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.photomath.detection.signature.patch.SignatureDetectionPatch
import app.revanced.patches.photomath.misc.unlockplus.annotations.UnlockPlusCompatibilty
import app.revanced.patches.photomath.misc.unlockplus.fingerprints.IsPlusUnlockedFingerprint
@Patch
@Name("unlock-plus")
@DependsOn([SignatureDetectionPatch::class])
@Description("Unlocks plus features.")
@UnlockPlusCompatibilty
@Compatibility([Package("com.microblink.photomath")])
@Version("0.0.1")
class UnlockPlusPatch : BytecodePatch(
listOf(
@@ -40,4 +41,4 @@ class UnlockPlusPatch : BytecodePatch(
return PatchResultSuccess()
}
}
}

View File

@@ -9,6 +9,7 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.Method
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
@@ -24,10 +25,21 @@ abstract class AbstractIntegrationsPatch(
* @see MethodFingerprint
*/
abstract class IntegrationsFingerprint(
returnType: String? = null,
access: Int? = null,
parameters: Iterable<String>? = null,
opcodes: Iterable<Opcode?>? = null,
strings: Iterable<String>? = null,
customFingerprint: ((methodDef: Method) -> Boolean)? = null,
private val contextRegisterResolver: (Method) -> Int = object : RegisterResolver {}
) : MethodFingerprint(strings = strings, customFingerprint = customFingerprint) {
) : MethodFingerprint(
returnType,
access,
parameters,
opcodes,
strings,
customFingerprint
) {
fun invoke(integrationsDescriptor: String): PatchResult {
result?.mutableMethod?.let { method ->
val contextRegister = contextRegisterResolver(method)

View File

@@ -30,7 +30,8 @@ class ClientSpoofPatch : BytecodePatch(
UserAgentHeaderBuilderFingerprint.result?.let { result ->
val insertIndex = result.scanResult.patternScanResult!!.endIndex
result.mutableMethod.apply {
val packageNameRegister = (instruction(insertIndex) as FiveRegisterInstruction).registerD
val packageNameRegister = instruction<FiveRegisterInstruction>(insertIndex).registerD
addInstruction(insertIndex, "const-string v$packageNameRegister, \"$ORIGINAL_PACKAGE_NAME\"")
}

View File

@@ -20,19 +20,18 @@ class VerticalScrollPatch : BytecodePatch(
listOf(CanScrollVerticallyFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = CanScrollVerticallyFingerprint.result ?: return CanScrollVerticallyFingerprint.toErrorResult()
CanScrollVerticallyFingerprint.result?.let {
it.mutableMethod.apply {
val moveResultIndex = it.scanResult.patternScanResult!!.endIndex
val moveResultRegister = instruction<OneRegisterInstruction>(moveResultIndex).registerA
with(result) {
val method = mutableMethod
val moveResultIndex = scanResult.patternScanResult!!.endIndex
val moveResultRegister = (method.instruction(moveResultIndex) as OneRegisterInstruction).registerA
method.addInstruction(
moveResultIndex + 1,
"const/4 v$moveResultRegister, 0x0"
)
}
val insertIndex = moveResultIndex + 1
addInstruction(
insertIndex,
"const/4 v$moveResultRegister, 0x0"
)
}
} ?: return CanScrollVerticallyFingerprint.toErrorResult()
return PatchResultSuccess()
}

View File

@@ -1,6 +1,8 @@
package app.revanced.patches.shared.settings.preference.impl
enum class InputType(val type: String) {
STRING("text"),
STRING("text"), // TODO: rename to "TEXT"
TEXT_CAP_CHARACTERS("textCapCharacters"),
TEXT_MULTI_LINE("textMultiLine"),
NUMBER("number"),
}

View File

@@ -23,7 +23,7 @@ internal class TextPreference(
val default: String? = null,
val summary: StringResource? = null
) : BasePreference(key, title) {
override val tag: String = "EditTextPreference"
override val tag: String = "app.revanced.integrations.settingsmenu.ResettableEditTextPreference"
override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element {
return super.serialize(ownerDocument, resourceCallback).apply {

View File

@@ -8,18 +8,13 @@ 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.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCompatibility
import app.revanced.patches.spotify.audio.fingerprints.DisableCaptureRestrictionAudioDriverFingerprint
import app.revanced.patches.spotify.audio.resource.patch.DisableCaptureRestrictionResourcePatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@Name("disable-capture-restriction")
@@ -35,49 +30,16 @@ class DisableCaptureRestrictionBytecodePatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult {
val method = DisableCaptureRestrictionAudioDriverFingerprint.result!!.mutableMethod
var invokePosition: Int? = null
var invokeParamRegister: Int? = null
// Find INVOKE_VIRTUAL opcode with call to AudioAttributesBuilder.setAllowedCapturePolicy(I)
for ((index, instruction) in method.implementation!!.instructions.withIndex()) {
if(instruction.opcode != Opcode.INVOKE_VIRTUAL)
continue
val methodName = ((instruction as ReferenceInstruction).reference as MethodReference).name
if (methodName != "setAllowedCapturePolicy")
continue
// Store register of the integer parameter for setAllowedCapturePolicy
invokeParamRegister = (instruction as FiveRegisterInstruction).registerD
invokePosition = index
}
if(invokePosition == null || invokeParamRegister == null)
return PatchResultError("Cannot find setAllowedCapturePolicy method call")
// Walk back to the const/4 instruction that sets the parameter register
var matchFound = false
for (index in invokePosition downTo 0) {
val instruction = method.instruction(index)
if(instruction.opcode != Opcode.CONST_4)
continue
val register = (instruction as OneRegisterInstruction).registerA
if(register != invokeParamRegister)
continue
// Replace parameter value
method.replaceInstruction(
index, "const/4 v$register, $ALLOW_CAPTURE_BY_ALL"
method.apply {
// Replace constant
val original = instruction(0) as OneRegisterInstruction
replaceInstruction(
0,
"const/4 v${original.registerA}, $ALLOW_CAPTURE_BY_ALL"
)
matchFound = true
break
}
return if (matchFound)
PatchResultSuccess()
else
PatchResultError("Const instruction not found")
return PatchResultSuccess()
}
private companion object {

View File

@@ -1,10 +1,27 @@
package app.revanced.patches.spotify.audio.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference
object DisableCaptureRestrictionAudioDriverFingerprint : MethodFingerprint(
"L",
AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.SYNTHETIC or AccessFlags.BRIDGE,
listOf("L"),
listOf(
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
),
customFingerprint = { methodDef ->
methodDef.definingClass == "Lcom/spotify/playback/playbacknative/AudioDriver;" && methodDef.name == "constructAudioAttributes"
// Check for method call to AudioAttributes$Builder.setAllowedCapturePolicy Android API
methodDef.implementation?.instructions?.any {
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "setAllowedCapturePolicy"
} == true
}
)

View File

@@ -0,0 +1,8 @@
package app.revanced.patches.syncforreddit.ads.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.laurencedawson.reddit_sync")])
@Target(AnnotationTarget.CLASS)
internal annotation class DisableAdsCompatibility

View File

@@ -0,0 +1,11 @@
package app.revanced.patches.syncforreddit.ads.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
object IsAdsEnabledFingerprint : MethodFingerprint(
returnType = "Z",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
strings = listOf("SyncIapHelper")
)

View File

@@ -0,0 +1,39 @@
package app.revanced.patches.syncforreddit.ads.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.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.syncforreddit.ads.annotations.DisableAdsCompatibility
import app.revanced.patches.syncforreddit.ads.fingerprints.IsAdsEnabledFingerprint
import app.revanced.patches.syncforreddit.detection.piracy.patch.DisablePiracyDetectionPatch
@Patch
@Name("disable-ads")
@DependsOn([DisablePiracyDetectionPatch::class])
@Description("Disables ads.")
@Version("0.0.1")
@DisableAdsCompatibility
class DisableAdsPatch : BytecodePatch(listOf(IsAdsEnabledFingerprint)) {
override fun execute(context: BytecodeContext): PatchResult {
IsAdsEnabledFingerprint.result?.mutableMethod?.apply {
addInstructions(
0,
"""
const/4 v0, 0x0
return v0
"""
)
} ?: return IsAdsEnabledFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -0,0 +1,29 @@
package app.revanced.patches.syncforreddit.detection.piracy.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.TypeReference
object PiracyDetectionFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL
),
customFingerprint = { method ->
method.implementation?.instructions?.any {
if (it.opcode != Opcode.NEW_INSTANCE) return@any false
val reference = (it as ReferenceInstruction).reference
reference.toString() == "Lcom/github/javiersantos/piracychecker/PiracyChecker;"
} ?: false
}
)

View File

@@ -0,0 +1,28 @@
package app.revanced.patches.syncforreddit.detection.piracy.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint
@Description("Disables detection of modified versions.")
@Version("0.0.1")
class DisablePiracyDetectionPatch : BytecodePatch(listOf(PiracyDetectionFingerprint)) {
override fun execute(context: BytecodeContext): PatchResult {
PiracyDetectionFingerprint.result?.mutableMethod?.apply {
addInstructions(
0,
"""
return-void
"""
)
} ?: return PiracyDetectionFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -36,7 +36,7 @@ class UnlockProPatch : BytecodePatch(
)
val setThemeMethod = SetThemeFingerprint.result!!.mutableMethod
setThemeMethod.removeInstructions(0, 9)
setThemeMethod.removeInstructions(0, 10)
return PatchResultSuccess()
}

View File

@@ -25,7 +25,6 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.iface.reference.StringReference
import org.jf.dexlib2.iface.reference.TypeReference
@Patch
@DependsOn([IntegrationsPatch::class])
@@ -96,7 +95,7 @@ class SettingsPatch : BytecodePatch(
private fun patchOptionNameAndOnClickEvent(index: Int, context: BytecodeContext) {
with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) {
// Patch option name
val overrideRegister = (instruction(index - 4) as OneRegisterInstruction).registerA
val overrideRegister = instruction<OneRegisterInstruction>(index - 4).registerA
replaceInstruction(
index - 4,
"""
@@ -105,16 +104,14 @@ class SettingsPatch : BytecodePatch(
)
// Patch option OnClick Event
with(((instruction(index) as ReferenceInstruction).reference as TypeReference).type) {
context.findClass(this)!!.mutableClass.methods.first { it.name == "onClick" }
.addInstructions(
0,
"""
invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V
return-void
"""
)
}
val type = instruction<ReferenceInstruction>(index).reference.toString()
context.findClass(type)!!.mutableClass.methods.first { type == "onClick" }.addInstructions(
0,
"""
invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V
return-void
"""
)
}
}
}

View File

@@ -97,14 +97,14 @@ class SpoofSimPatch : BytecodePatch() {
// Patch Android API and return fake sim information
private fun MutableMethod.replaceReference(index: Int, replacement: String) {
val resultReg = (instruction(index + 1) as OneRegisterInstruction).registerA
val resultReg = instruction<OneRegisterInstruction>(index + 1).registerA
addInstructions(
index + 2,
"""
invoke-static {v$resultReg}, Lapp/revanced/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$resultReg
"""
"""
invoke-static {v$resultReg}, Lapp/revanced/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$resultReg
"""
)
}
}

View File

@@ -38,7 +38,7 @@ class UnlockPaidWidgetsPatch : BytecodePatch(
fingerprint.result?.mutableMethod ?: return fingerprint.toErrorResult()
}.forEach { method ->
method.apply {
removeInstructions(4, 2)
removeInstructions(4, 3)
addInstructions(
implementation?.instructions?.size!!, """
const/4 v1, 0x0

View File

@@ -4,8 +4,12 @@ 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.*
import app.revanced.patcher.patch.*
import app.revanced.patcher.extensions.addInstruction
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
@@ -13,7 +17,9 @@ import app.revanced.patches.shared.settings.preference.impl.ArrayResource
import app.revanced.patches.shared.settings.preference.impl.ListPreference
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.twitch.chat.antidelete.annotations.ShowDeletedMessagesCompatibility
import app.revanced.patches.twitch.chat.antidelete.fingerprints.*
import app.revanced.patches.twitch.chat.antidelete.fingerprints.ChatUtilCreateDeletedSpanFingerprint
import app.revanced.patches.twitch.chat.antidelete.fingerprints.DeletedMessageClickableSpanCtorFingerprint
import app.revanced.patches.twitch.chat.antidelete.fingerprints.SetHasModAccessFingerprint
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch

View File

@@ -4,7 +4,9 @@ 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.*
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
@@ -19,7 +21,10 @@ import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen
import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.twitch.misc.settings.annotations.SettingsCompatibility
import app.revanced.patches.twitch.misc.settings.components.CustomPreferenceCategory
import app.revanced.patches.twitch.misc.settings.fingerprints.*
import app.revanced.patches.twitch.misc.settings.fingerprints.MenuGroupsOnClickFingerprint
import app.revanced.patches.twitch.misc.settings.fingerprints.MenuGroupsUpdatedFingerprint
import app.revanced.patches.twitch.misc.settings.fingerprints.SettingsActivityOnCreateFingerprint
import app.revanced.patches.twitch.misc.settings.fingerprints.SettingsMenuItemEnumFingerprint
import app.revanced.patches.twitch.misc.settings.resource.patch.SettingsResourcePatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.immutable.ImmutableField

View File

@@ -61,7 +61,7 @@ class HideViewsBytecodePatch : BytecodePatch(
TweetStatsContainerConstructorFingerprint,
returnFingerprint
) { patternScanResult, method ->
method.removeInstructions(patternScanResult.endIndex - 3, 2)
method.removeInstructions(patternScanResult.endIndex - 3, 3)
}
}
@@ -80,13 +80,13 @@ class HideViewsBytecodePatch : BytecodePatch(
TweetStatsContainerWrapperConstructorFingerprint,
wrapperReturnFingerprint
) { patternScanResult, method ->
method.removeInstructions(patternScanResult.startIndex - 4, 3)
method.removeInstructions(patternScanResult.startIndex - 4, 4)
}
}
private fun removeViewDelegateBinderSubscription() {
transformMethod(TweetStatsViewDelegateBinderFingerprint) { result, method ->
method.removeInstructions(result.scanResult.patternScanResult!!.startIndex - 4, 9)
method.removeInstructions(result.scanResult.patternScanResult!!.startIndex - 4, 10)
}
}

View File

@@ -1,6 +1,7 @@
package app.revanced.patches.youtube.ad.general.bytecode.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -9,16 +10,15 @@ 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.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.misc.fix.verticalscroll.patch.VerticalScrollPatch
import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility
import app.revanced.patches.youtube.ad.general.bytecode.fingerprints.ReelConstructorFingerprint
import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch
import app.revanced.patches.youtube.misc.fix.backtoexitgesture.patch.FixBackToExitGesturePatch
import app.revanced.patches.shared.misc.fix.verticalscroll.patch.VerticalScrollPatch
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@@ -71,20 +71,16 @@ class GeneralAdsPatch : BytecodePatch(
}
}
with(
ReelConstructorFingerprint.result
?: return PatchResultError("Could not resolve fingerprint")
) {
ReelConstructorFingerprint.result?.let {
// iput-object v$viewRegister, ...
val insertIndex = this.scanResult.patternScanResult!!.startIndex + 2
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2
with(this.mutableMethod) {
val viewRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA
it.mutableMethod.apply {
val viewRegister = instruction<TwoRegisterInstruction>(insertIndex).registerA
injectHideCall(insertIndex, viewRegister, "hideReelView")
}
}
} ?: return ReelConstructorFingerprint.toErrorResult()
return PatchResultSuccess()
}

View File

@@ -69,7 +69,7 @@ class HideAutoplayButtonPatch : BytecodePatch(
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction
// can be clobbered because this register is overwritten after the injected code
val clobberRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA
val clobberRegister = instruction<OneRegisterInstruction>(insertIndex).registerA
addInstructions(
insertIndex,

View File

@@ -149,7 +149,7 @@ class NavigationButtonsPatch : BytecodePatch(listOf(AddCreateButtonViewFingerpri
}!!.index
val conditionalCheckIndex = stringIndex - 1
val conditionRegister = (instruction(conditionalCheckIndex) as OneRegisterInstruction).registerA
val conditionRegister = instruction<OneRegisterInstruction>(conditionalCheckIndex).registerA
addInstructions(
conditionalCheckIndex,

View File

@@ -20,7 +20,7 @@ internal object InjectionUtils {
// Register to pass to the hook
val registerIndex = insertIndex - 1 // MOVE_RESULT_OBJECT is always the previous instruction
val register = (injectTarget.instruction(registerIndex) as OneRegisterInstruction).registerA
val register = injectTarget.instruction<OneRegisterInstruction>(registerIndex).registerA
injectTarget.addInstruction(
insertIndex,

View File

@@ -12,16 +12,12 @@ import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.youtube.layout.buttons.player.background.annotations.PlayerButtonBackgroundCompatibility
import org.w3c.dom.Element
@Patch
@Patch(false)
@Name("remove-player-button-background")
@Description("Removes the background from the video player buttons.")
@PlayerButtonBackgroundCompatibility
@Version("0.0.1")
class PlayerButtonBackgroundPatch : ResourcePatch {
private companion object {
const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml"
}
override fun execute(context: ResourceContext): PatchResult {
context.xmlEditor[RESOURCE_FILE_PATH].use { editor ->
editor.file.doRecursively node@{ node ->
@@ -35,4 +31,8 @@ class PlayerButtonBackgroundPatch : ResourcePatch {
return PatchResultSuccess()
}
private companion object {
const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml"
}
}

View File

@@ -55,7 +55,7 @@ class HidePlayerButtonsPatch : BytecodePatch(
PlayerControlsVisibilityModelFingerprint.result?.apply {
val callIndex = scanResult.patternScanResult!!.endIndex
val callInstruction = mutableMethod.instruction(callIndex) as Instruction3rc
val callInstruction = mutableMethod.instruction<Instruction3rc>(callIndex)
// overriding this parameter register hides the previous and next buttons
val hasNextParameterRegister = callInstruction.startRegister + ParameterOffsets.HAS_NEXT

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.albumcards.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
@@ -29,16 +30,22 @@ class AlbumCardsPatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val albumCardsResult = AlbumCardsFingerprint.result!!
val albumCardsMethod = albumCardsResult.mutableMethod
AlbumCardsFingerprint.result?.let {
it.mutableMethod.apply {
val checkCastAnchorIndex = it.scanResult.patternScanResult!!.endIndex
val insertIndex = checkCastAnchorIndex + 1
val checkCastAnchorIndex = albumCardsResult.scanResult.patternScanResult!!.endIndex
val albumCardViewRegister = instruction<OneRegisterInstruction>(checkCastAnchorIndex).registerA
albumCardsMethod.addInstruction(
checkCastAnchorIndex + 1, """
invoke-static {v${(albumCardsMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideAlbumCardsPatch;->hideAlbumCards(Landroid/view/View;)V
"""
)
addInstruction(
insertIndex,
"invoke-static {v$albumCardViewRegister}, " +
"Lapp/revanced/integrations/patches/HideAlbumCardsPatch;" +
"->" +
"hideAlbumCards(Landroid/view/View;)V"
)
}
} ?: return AlbumCardsFingerprint.toErrorResult()
return PatchResultSuccess()
}

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.breakingnews.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
@@ -24,22 +25,29 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@BreakingNewsCompatibility
@Version("0.0.1")
class BreakingNewsPatch : BytecodePatch(
listOf(
BreakingNewsFingerprint,
)
listOf(BreakingNewsFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val breakingNewsResult = BreakingNewsFingerprint.result!!
val breakingNewsMethod = breakingNewsResult.mutableMethod
BreakingNewsFingerprint.result?.let {
val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1
val moveResultIndex = insertIndex - 1
val moveResultObjectIndex =
breakingNewsResult.scanResult.patternScanResult!!.endIndex - 2
it.mutableMethod.apply {
val breakingNewsViewRegister = instruction<OneRegisterInstruction>(moveResultIndex).registerA
addInstruction(
insertIndex,
"""
invoke-static {v$breakingNewsViewRegister},
Lapp/revanced/integrations/patches/HideBreakingNewsPatch;
->
hideBreakingNews(Landroid/view/View;)V
"""
)
}
} ?: return BreakingNewsFingerprint.toErrorResult()
breakingNewsMethod.addInstruction(
moveResultObjectIndex + 1, """
invoke-static {v${(breakingNewsMethod.instruction(moveResultObjectIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideBreakingNewsPatch;->hideBreakingNews(Landroid/view/View;)V
"""
)
return PatchResultSuccess()
}

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.comments.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
@@ -32,9 +33,6 @@ class CommentsPatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val shortsCommentsButtonResult = ShortsCommentsButtonFingerprint.result!!
val shortsCommentsButtonMethod = shortsCommentsButtonResult.mutableMethod
val checkCastAnchorFingerprint = object : MethodFingerprint(
opcodes = listOf(
Opcode.CONST,
@@ -47,15 +45,24 @@ class CommentsPatch : BytecodePatch(
)
) {}
val checkCastAnchorIndex = checkCastAnchorFingerprint.also {
it.resolve(context, shortsCommentsButtonMethod, shortsCommentsButtonResult.classDef)
}.result!!.scanResult.patternScanResult!!.endIndex
ShortsCommentsButtonFingerprint.result?.let {
it.mutableMethod.apply {
val checkCastAnchorIndex = checkCastAnchorFingerprint.also { result ->
if (!result.resolve(context, this, it.classDef))
throw checkCastAnchorFingerprint.toErrorResult()
}.result!!.scanResult.patternScanResult!!.endIndex
shortsCommentsButtonMethod.addInstructions(
checkCastAnchorIndex + 1, """
invoke-static {v${(shortsCommentsButtonMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideShortsCommentsButtonPatch;->hideShortsCommentsButton(Landroid/view/View;)V
"""
)
val shortsCommentsButtonRegister = instruction<OneRegisterInstruction>(checkCastAnchorIndex).registerA
val insertIndex = checkCastAnchorIndex + 1
addInstructions(
insertIndex,
"""
invoke-static { v$shortsCommentsButtonRegister }, Lapp/revanced/integrations/patches/HideShortsCommentsButtonPatch;->hideShortsCommentsButton(Landroid/view/View;)V
"""
)
}
} ?: return ShortsCommentsButtonFingerprint.toErrorResult()
return PatchResultSuccess()
}

View File

@@ -33,7 +33,7 @@ class CrowdfundingBoxPatch : BytecodePatch(
CrowdfundingBoxFingerprint.result?.let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
val objectRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA
val objectRegister = instruction<TwoRegisterInstruction>(insertIndex).registerA
addInstruction(insertIndex, "invoke-static {v$objectRegister}, $INTEGRATIONS_METHOD_DESCRIPTOR")
}

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.endscreencards.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
@@ -35,19 +36,23 @@ class HideEndscreenCardsPatch : BytecodePatch(
) {
override fun execute(context: BytecodeContext): PatchResult {
fun MethodFingerprint.injectHideCall() {
val layoutResult = result!!
val layoutMethod = layoutResult.mutableMethod
val layoutResult = result ?: throw toErrorResult()
layoutResult.mutableMethod.apply {
val insertIndex = layoutResult.scanResult.patternScanResult!!.endIndex + 1
val viewRegister = instruction<Instruction21c>(insertIndex - 1).registerA
val checkCastIndex = layoutResult.scanResult.patternScanResult!!.endIndex
val viewRegister = (layoutMethod.instruction(checkCastIndex) as Instruction21c).registerA
layoutMethod.addInstruction(
checkCastIndex + 1,
"invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V"
)
addInstruction(
insertIndex,
"invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V"
)
}
}
listOf(LayoutCircleFingerprint, LayoutIconFingerprint, LayoutVideoFingerprint).forEach(MethodFingerprint::injectHideCall)
listOf(
LayoutCircleFingerprint,
LayoutIconFingerprint,
LayoutVideoFingerprint
).forEach(MethodFingerprint::injectHideCall)
return PatchResultSuccess()
}

View File

@@ -29,7 +29,7 @@ class HideFloatingMicrophoneButtonPatch : BytecodePatch(
ShowFloatingMicrophoneButtonFingerprint.result?.let { result ->
with(result.mutableMethod) {
val insertIndex = result.scanResult.patternScanResult!!.startIndex + 1
val showButtonRegister = (instruction(insertIndex - 1) as TwoRegisterInstruction).registerA
val showButtonRegister = instruction<TwoRegisterInstruction>(insertIndex - 1).registerA
addInstructions(
insertIndex,

View File

@@ -45,8 +45,9 @@ class HideGetPremiumPatch : BytecodePatch(
GetPremiumViewFingerprint.result?.let {
it.mutableMethod.apply {
val startIndex = it.scanResult.patternScanResult!!.startIndex
val measuredWidthRegister = (instruction(startIndex) as TwoRegisterInstruction).registerA
val measuredHeightInstruction = instruction(startIndex + 1) as TwoRegisterInstruction
val measuredWidthRegister = instruction<TwoRegisterInstruction>(startIndex).registerA
val measuredHeightInstruction = instruction<TwoRegisterInstruction>(startIndex + 1)
val measuredHeightRegister = measuredHeightInstruction.registerA
val tempRegister = measuredHeightInstruction.registerB

View File

@@ -20,7 +20,8 @@ import app.revanced.patches.youtube.layout.hide.infocards.fingerprints.Infocards
import app.revanced.patches.youtube.layout.hide.infocards.resource.patch.HideInfocardsResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@Patch
@DependsOn([IntegrationsPatch::class, HideInfocardsResourcePatch::class])
@@ -35,18 +36,17 @@ class HideInfoCardsPatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
with(InfocardsIncognitoFingerprint.also {
InfocardsIncognitoFingerprint.also {
it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef)
}.result!!.mutableMethod) {
}.result!!.mutableMethod.apply {
val invokeInstructionIndex = implementation!!.instructions.indexOfFirst {
it.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal &&
((it as? BuilderInstruction35c)?.reference.toString() ==
"Landroid/view/View;->setVisibility(I)V")
((it as ReferenceInstruction).reference.toString() == "Landroid/view/View;->setVisibility(I)V")
}
addInstructions(
invokeInstructionIndex,
"invoke-static {v${(instruction(invokeInstructionIndex) as? BuilderInstruction35c)?.registerC}}," +
"invoke-static {v${instruction<FiveRegisterInstruction>(invokeInstructionIndex).registerC}}," +
" Lapp/revanced/integrations/patches/HideInfoCardsPatch;->hideInfoCardsIncognito(Landroid/view/View;)V"
)
}

View File

@@ -0,0 +1,25 @@
package app.revanced.patches.youtube.layout.hide.loadmorebutton.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf(
"17.49.37",
"18.03.36",
"18.03.42",
"18.04.35",
"18.04.41",
"18.05.32",
"18.05.35",
"18.05.40",
"18.08.37",
"18.15.40",
"18.16.37"
)
)]
)
@Target(AnnotationTarget.CLASS)
internal annotation class HideLoadMoreButtonCompatibility

View File

@@ -0,0 +1,29 @@
package app.revanced.patches.youtube.layout.hide.loadmorebutton.bytecode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.hide.loadmorebutton.resource.patch.HideLoadMoreButtonResourcePatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
object HideLoadMoreButtonFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "L", "L", "L"),
opcodes = listOf(
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT
),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any {
if (it.opcode != Opcode.CONST) return@any false
val literal = (it as WideLiteralInstruction).wideLiteral
literal == HideLoadMoreButtonResourcePatch.expandButtonDownId
} ?: false
}
)

View File

@@ -0,0 +1,48 @@
package app.revanced.patches.youtube.layout.hide.loadmorebutton.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.loadmorebutton.bytecode.fingerprints.HideLoadMoreButtonFingerprint
import app.revanced.patches.youtube.layout.hide.loadmorebutton.resource.patch.HideLoadMoreButtonResourcePatch
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch
@Name("hide-load-more-button")
@Description("Hides the button under videos that loads similar videos.")
@DependsOn([HideLoadMoreButtonResourcePatch::class])
@Version("0.0.1")
class HideLoadMoreButtonPatch : BytecodePatch(listOf(HideLoadMoreButtonFingerprint)) {
override fun execute(context: BytecodeContext): PatchResult {
HideLoadMoreButtonFingerprint.result?.let {
it.mutableMethod.apply {
val moveRegisterIndex = it.scanResult.patternScanResult!!.endIndex
val viewRegister = instruction<OneRegisterInstruction>(moveRegisterIndex).registerA
val insertIndex = moveRegisterIndex + 1
addInstruction(
insertIndex,
"invoke-static { v$viewRegister }, " +
"$INTEGRATIONS_CLASS_DESCRIPTOR->hideLoadMoreButton(Landroid/view/View;)V"
)
}
} ?: return HideLoadMoreButtonFingerprint.toErrorResult()
return PatchResultSuccess()
}
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/patches/HideLoadMoreButtonPatch;"
}
}

View File

@@ -0,0 +1,40 @@
package app.revanced.patches.youtube.layout.hide.loadmorebutton.resource.patch
import app.revanced.patcher.annotation.Name
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.loadmorebutton.annotations.HideLoadMoreButtonCompatibility
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
@Name("hide-load-more-button-resource-patch")
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
@HideLoadMoreButtonCompatibility
class HideLoadMoreButtonResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_hide_load_more_button",
StringResource("revanced_hide_load_more_button_title", "Hide Load More button"),
true,
StringResource("revanced_hide_load_more_button_summary_on", "Load More button is hidden"),
StringResource("revanced_hide_load_more_button_summary_off", "Load More button is shown")
)
)
expandButtonDownId = ResourceMappingPatch.resourceMappings.single {
it.type == "layout" && it.name == "expand_button_down"
}.id
return PatchResultSuccess()
}
internal companion object {
var expandButtonDownId: Long = -1
}
}

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.youtube.layout.hide.personalinformation.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
@@ -29,23 +30,22 @@ class HideEmailAddressPatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val accountSwitcherAccessibilityLabelResult = AccountSwitcherAccessibilityLabelFingerprint.result!!
val accountSwitcherAccessibilityLabelMethod = accountSwitcherAccessibilityLabelResult.mutableMethod
AccountSwitcherAccessibilityLabelFingerprint.result?.let {
it.mutableMethod.apply {
val setVisibilityConstIndex = it.scanResult.patternScanResult!!.endIndex
val setVisibilityConstIndex =
accountSwitcherAccessibilityLabelResult.scanResult.patternScanResult!!.endIndex
val setVisibilityConstRegister =
instruction<OneRegisterInstruction>(setVisibilityConstIndex - 2).registerA
val setVisibilityConstRegister = (
accountSwitcherAccessibilityLabelMethod.instruction
(setVisibilityConstIndex - 2) as OneRegisterInstruction
).registerA
accountSwitcherAccessibilityLabelMethod.addInstructions(
setVisibilityConstIndex, """
invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I
move-result v$setVisibilityConstRegister
"""
)
addInstructions(
setVisibilityConstIndex,
"""
invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I
move-result v$setVisibilityConstRegister
"""
)
}
} ?: return AccountSwitcherAccessibilityLabelFingerprint.toErrorResult()
return PatchResultSuccess()
}

View File

@@ -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
}
)

View File

@@ -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;"
}
}

View File

@@ -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"
}
}

View File

@@ -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
}
}

View File

@@ -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.SwitchPreference
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.settings.bytecode.patch.SettingsPatch
@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")
@Description("Hides the seekbar.")
@HideSeekbarCompatibility

View File

@@ -102,18 +102,21 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!!
.scanResult.patternScanResult!!.startIndex
val insertIndex = atomicReferenceStartIndex + 8
textComponentContextFingerprintResult.mutableMethod.apply {
// Get the conversion context obfuscated field name, and the registers for the AtomicReference and CharSequence
val conversionContextFieldReference =
(instruction(conversionContextIndex) as ReferenceInstruction).reference
instruction<ReferenceInstruction>(conversionContextIndex).reference
// any free register
val contextRegister =
(instruction(atomicReferenceStartIndex) as TwoRegisterInstruction).registerB
val atomicReferenceRegister =
(instruction(atomicReferenceStartIndex + 5) as FiveRegisterInstruction).registerC
instruction<TwoRegisterInstruction>(atomicReferenceStartIndex).registerB
val insertIndex = atomicReferenceStartIndex + 8
val moveCharSequenceInstruction = instruction(insertIndex) as TwoRegisterInstruction
val atomicReferenceRegister =
instruction<FiveRegisterInstruction>(atomicReferenceStartIndex + 5).registerC
val moveCharSequenceInstruction = instruction<TwoRegisterInstruction>(insertIndex)
val charSequenceRegister = moveCharSequenceInstruction.registerB
// Insert as first instructions at the control flow label.
@@ -145,8 +148,8 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
return PatchResultError("Method signature did not match: $this $parameterTypes")
val insertIndex = implementation!!.instructions.size - 1
val spannedParameterRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA
val parameter = (instruction(insertIndex - 2) as BuilderInstruction35c).reference
val spannedParameterRegister = instruction<OneRegisterInstruction>(insertIndex).registerA
val parameter = instruction<BuilderInstruction35c>(insertIndex - 2).reference
if (!parameter.toString().endsWith("Landroid/text/Spanned;"))
return PatchResultError("Method signature parameter did not match: $parameter")
@@ -171,9 +174,12 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
DislikesOldLayoutTextViewFingerprint.result?.let {
it.mutableMethod.apply {
val startIndex = it.scanResult.patternScanResult!!.startIndex
val resourceIdentifierRegister = (instruction(startIndex) as OneRegisterInstruction).registerA
val textViewRegister = (instruction(startIndex + 4) as OneRegisterInstruction).registerA
addInstruction(startIndex + 4,
val resourceIdentifierRegister = instruction<OneRegisterInstruction>(startIndex).registerA
val textViewRegister = instruction<OneRegisterInstruction>(startIndex + 4).registerA
addInstruction(
startIndex + 4,
"invoke-static {v$resourceIdentifierRegister, v$textViewRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setOldUILayoutDislikes(ILandroid/widget/TextView;)V"
)
}

View File

@@ -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

View File

@@ -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
}
)

View File

@@ -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 org.jf.dexlib2.Opcode

View File

@@ -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;"
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}
}

View File

@@ -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.fingerprint.method.impl.MethodFingerprint

View File

@@ -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
}
}
}

View File

@@ -1,77 +1,51 @@
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.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.*
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility
import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint
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.seekbar.bytecode.patch.SeekbarColorBytecodePatch
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.resource.ThemeResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch
@Name("theme")
@Description("Applies a custom theme.")
@DependsOn([ThemeLithoComponentsPatch::class, ThemeResourcePatch::class, IntegrationsPatch::class])
@ThemeCompatibility
@DependsOn([LithoColorHookPatch::class, SeekbarColorBytecodePatch::class, ThemeResourcePatch::class])
@Version("0.0.1")
class ThemeBytecodePatch : BytecodePatch(
listOf(CreateDarkThemeSeekbarFingerprint, SetSeekbarClickedColorFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
CreateDarkThemeSeekbarFingerprint.result?.let {
val putColorValueIndex = it.method.indexOfInstructionWithSeekbarId!! + 3
LithoColorHookPatch.lithoColorOverrideHook(INTEGRATIONS_CLASS_DESCRIPTOR, "getValue")
it.mutableMethod.apply {
val overrideRegister = (instruction(putColorValueIndex) as TwoRegisterInstruction).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(0) as TwoRegisterInstruction).registerA
addInstructions(
0,
"""
invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarClickedColorValue(I)I
move-result v$colorRegister
"""
)
}
}
} ?: return SetSeekbarClickedColorFingerprint.toErrorResult()
return PatchResultSuccess()
}
private companion object {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemePatch;"
companion object : OptionsContainer() {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemeLithoComponentsPatch;"
var darkThemeBackgroundColor: String? by option(
PatchOption.StringOption(
key = "darkThemeBackgroundColor",
default = "@android:color/black",
title = "Background color for the dark theme",
description = "The background color of the dark theme. Can be a hex color or a resource reference.",
)
)
var lightThemeBackgroundColor: String? by option(
PatchOption.StringOption(
key = "lightThemeBackgroundColor",
default = "@android:color/white",
title = "Background color for the light theme",
description = "The background color of the light theme. Can be a hex color or a resource reference.",
)
)
}
}

View File

@@ -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;"
}
}

View File

@@ -7,6 +7,8 @@ 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.StringResource
import app.revanced.patches.shared.settings.preference.impl.TextPreference
import app.revanced.patches.youtube.layout.theme.bytecode.patch.ThemeBytecodePatch.Companion.darkThemeBackgroundColor
import app.revanced.patches.youtube.layout.theme.bytecode.patch.ThemeBytecodePatch.Companion.lightThemeBackgroundColor
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.copyResources
@@ -20,22 +22,14 @@ class ThemeResourcePatch : ResourcePatch {
"revanced_seekbar_color",
StringResource("revanced_seekbar_color_title", "Seekbar color"),
InputType.STRING,
"#ffff0000",
"#FF0000",
StringResource(
"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 lightThemeBackgroundColor = lightThemeBackgroundColor!!
@@ -67,25 +61,4 @@ class ThemeResourcePatch : ResourcePatch {
return PatchResultSuccess()
}
companion object : OptionsContainer() {
internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L
var darkThemeBackgroundColor: String? by option(
PatchOption.StringOption(
key = "darkThemeBackgroundColor",
default = "@android:color/black",
title = "Background color for the dark theme",
description = "The background color of the dark theme. Can be a hex color or a resource reference.",
)
)
var lightThemeBackgroundColor: String? by option(
PatchOption.StringOption(
key = "lightThemeBackgroundColor",
default = "@android:color/white",
title = "Background color for the light theme",
description = "The background color of the light theme. Can be a hex color or a resource reference.",
)
)
}
}

View File

@@ -0,0 +1,15 @@
package app.revanced.patches.youtube.misc.integrations.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint
import org.jf.dexlib2.AccessFlags
object EmbeddedPlayerControlsOverlayFingerprint : IntegrationsFingerprint(
access = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR,
returnType = "V",
parameters = listOf("L", "L", "L"),
customFingerprint = { methodDef ->
methodDef.definingClass.startsWith("Lcom/google/android/apps/youtube/embeddedplayer/service/ui/overlays/controlsoverlay/remoteloaded/")
},
contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size }
)

View File

@@ -5,6 +5,7 @@ import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch
import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility
import app.revanced.patches.youtube.misc.integrations.fingerprints.InitFingerprint
import app.revanced.patches.youtube.misc.integrations.fingerprints.EmbeddedPlayerControlsOverlayFingerprint
import app.revanced.patches.youtube.misc.integrations.fingerprints.ServiceFingerprint
import app.revanced.patches.youtube.misc.integrations.fingerprints.StandalonePlayerFingerprint
@@ -13,5 +14,5 @@ import app.revanced.patches.youtube.misc.integrations.fingerprints.StandalonePla
@RequiresIntegrations
class IntegrationsPatch : AbstractIntegrationsPatch(
"Lapp/revanced/integrations/utils/ReVancedUtils;",
listOf(InitFingerprint, StandalonePlayerFingerprint, ServiceFingerprint),
listOf(InitFingerprint, StandalonePlayerFingerprint, ServiceFingerprint, EmbeddedPlayerControlsOverlayFingerprint),
)

View File

@@ -54,7 +54,7 @@ class VideoInformationPatch : BytecodePatch(
playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
// hook the player controller for use through integrations
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "playerController_onCreateHook")
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
// seek method
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method
@@ -93,7 +93,7 @@ class VideoInformationPatch : BytecodePatch(
with(videoLengthMethodResult.mutableMethod) {
val videoLengthRegisterIndex = videoLengthMethodResult.scanResult.patternScanResult!!.endIndex - 2
val videoLengthRegister = (instruction(videoLengthRegisterIndex) as OneRegisterInstruction).registerA
val videoLengthRegister = instruction<OneRegisterInstruction>(videoLengthRegisterIndex).registerA
val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide
addInstruction(
@@ -140,7 +140,7 @@ class VideoInformationPatch : BytecodePatch(
speedSelectionInsertMethod = mutableMethod
speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3
speedSelectionValueRegister =
(mutableMethod.instruction(speedSelectionInsertIndex) as FiveRegisterInstruction).registerD
mutableMethod.instruction<FiveRegisterInstruction>(speedSelectionInsertIndex).registerD
val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions
setPlaybackSpeedContainerClassFieldReference =
@@ -160,24 +160,32 @@ class VideoInformationPatch : BytecodePatch(
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/VideoInformation;"
private lateinit var playerInitMethod: MutableMethod
private var playerInitInsertIndex = 4
private lateinit var timeMethod: MutableMethod
private var timeInitInsertIndex = 2
private lateinit var highPrecisionTimeMethod: MutableMethod
private var highPrecisionInsertIndex = 0
private fun MutableMethod.insert(insert: InsertIndex, register: String, descriptor: String) =
addInstruction(insert.index, "invoke-static { $register }, $descriptor")
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
private fun MutableMethod.insertTimeHook(insert: InsertIndex, descriptor: String) =
insert(insert, "p1, p2", descriptor)
private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) =
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 targetMethodName The name of the static method to invoke when the player controller is created.
*/
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
playerInitMethod.insert(
InsertIndex.CREATE,
playerInitInsertIndex++,
"v0",
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
)
@@ -191,7 +199,7 @@ class VideoInformationPatch : BytecodePatch(
*/
internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) =
timeMethod.insertTimeHook(
InsertIndex.TIME,
timeInitInsertIndex++,
"$targetMethodClass->$targetMethodName(J)V"
)
@@ -205,16 +213,10 @@ class VideoInformationPatch : BytecodePatch(
*/
internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) =
highPrecisionTimeMethod.insertTimeHook(
InsertIndex.HIGH_PRECISION_TIME,
highPrecisionInsertIndex++,
"$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) =
instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference

View File

@@ -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.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
import app.revanced.patches.youtube.misc.video.quality.annotations.RememberVideoQualityCompatibility
import app.revanced.patches.youtube.misc.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint
import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint
import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualitySetterFingerprint
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@Patch
@DependsOn([IntegrationsPatch::class, VideoIdPatch::class, SettingsPatch::class])
@DependsOn([IntegrationsPatch::class, VideoInformationPatch::class, SettingsPatch::class])
@Name("remember-video-quality")
@Description("Adds the ability to remember the video quality you chose in the video quality flyout.")
@RememberVideoQualityCompatibility
@@ -114,7 +114,7 @@ class RememberVideoQualityPatch : BytecodePatch(
* 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.
VideoQualitySetterFingerprint.result?.also {

View File

@@ -0,0 +1,24 @@
package app.revanced.patches.youtube.misc.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.misc.video.speed.custom.patch.CustomVideoSpeedPatch
import app.revanced.patches.youtube.misc.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 sub patches succeeded.
}
}

View File

@@ -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>"
}
)

View File

@@ -8,37 +8,47 @@ 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.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.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.")
@Description("Adds custom video speed options.")
@DependsOn([IntegrationsPatch::class])
@CustomPlaybackSpeedCompatibility
@Version("0.0.1")
class CustomVideoSpeedPatch : BytecodePatch(
listOf(
SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint, VideoSpeedPatchFingerprint
SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val speedLimitMin = minVideoSpeed!!.toFloat()
val speedLimitMax = maxVideoSpeed!!.toFloat().coerceAtLeast(speedLimitMin)
val speedsGranularity = videoSpeedsGranularity!!.toFloat()
SettingsPatch.PreferenceScreen.MISC.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!!
@@ -61,7 +71,7 @@ class CustomVideoSpeedPatch : BytecodePatch(
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->videoSpeeds:[F"
val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->customVideoSpeeds:[F"
arrayGenMethod.addInstructions(
arrayLengthConstIndex + 1,
@@ -96,100 +106,17 @@ class CustomVideoSpeedPatch : BytecodePatch(
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
// edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x
limiterMethod.replaceInstruction(
limiterMinConstIndex,
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
"sget v$limiterMinConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->minVideoSpeed:F"
)
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
)
"sget v$limiterMaxConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->maxVideoSpeed:F"
)
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)
}
)
}
}

View File

@@ -7,7 +7,9 @@ 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.*
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
@@ -19,14 +21,13 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch
import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference
import app.revanced.patches.youtube.misc.video.speed.custom.patch.CustomVideoSpeedPatch
import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
@Patch
@Name("remember-playback-speed")
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class, VideoInformationPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomVideoSpeedPatch::class])
@RememberPlaybackSpeedCompatibility
@Version("0.0.1")
class RememberPlaybackSpeedPatch : BytecodePatch(
@@ -75,8 +76,7 @@ class RememberPlaybackSpeedPatch : BytecodePatch(
)
)
VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V")
VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted")
VideoInformationPatch.userSelectedPlaybackSpeedHook(
INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed")

View File

@@ -33,7 +33,7 @@ class VideoIdPatch : BytecodePatch(
result.mutableMethod.also {
insertMethod = it
}.apply {
videoIdRegister = (instruction(videoIdRegisterInstructionIndex) as OneRegisterInstruction).registerA
videoIdRegister = instruction<OneRegisterInstruction>(videoIdRegisterInstructionIndex).registerA
insertIndex = videoIdRegisterInstructionIndex + 1
}
} ?: return VideoIdFingerprint.toErrorResult()
@@ -44,7 +44,7 @@ class VideoIdPatch : BytecodePatch(
result.mutableMethod.also {
backgroundPlaybackMethod = it
}.apply {
backgroundPlaybackVideoIdRegister = (instruction(endIndex + 1) as OneRegisterInstruction).registerA
backgroundPlaybackVideoIdRegister = instruction<OneRegisterInstruction>(endIndex + 1).registerA
backgroundPlaybackInsertIndex = endIndex + 2
}
} ?: return VideoIdFingerprintBackgroundPlay.toErrorResult()

View File

@@ -12,9 +12,9 @@ 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.youtube.misc.settings.bytecode.patch.SettingsPatch
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
import app.revanced.patches.youtube.misc.zoomhaptics.annotations.ZoomHapticsCompatibility
import app.revanced.patches.youtube.misc.zoomhaptics.fingerprints.ZoomHapticsFingerprint

View File

@@ -32,7 +32,7 @@ class HideAdsPatch : BytecodePatch(
ContainsAdFingerprint.result?.let { result ->
result.mutableMethod.apply {
val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1
val adsListRegister = (instruction(insertIndex - 2) as Instruction21c).registerA
val adsListRegister = instruction<Instruction21c>(insertIndex - 2).registerA
listOf(
"_buttoned_layout",

View 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
}

View File

@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="revanced_settings_confirm_user_dialog_title">Do you wish to proceed?</string>
<string name="revanced_settings_reset">Reset</string>
</resources>