mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-25 11:41:04 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6580f71392 | ||
|
|
9c57961680 | ||
|
|
1d7a9ac437 | ||
|
|
51e08fb0b6 | ||
|
|
91feea1c50 | ||
|
|
fc8bfff427 | ||
|
|
9a3307c1b1 | ||
|
|
eff806c5e3 | ||
|
|
b45a44ff3f | ||
|
|
391e8fa8f6 | ||
|
|
dbf0668f28 | ||
|
|
b228640e4f | ||
|
|
0ddb2df640 | ||
|
|
c9525d0c26 | ||
|
|
3c5832eda2 | ||
|
|
eef7e87bbf | ||
|
|
535f621f20 | ||
|
|
695a0d14ad | ||
|
|
f70e54545b | ||
|
|
353f036a72 |
61
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
Normal file
61
.github/ISSUE_TEMPLATE/bug-issue.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: 🐞 Bug report
|
||||||
|
description: Report a very clearly broken issue.
|
||||||
|
title: 'bug: <title>'
|
||||||
|
labels: [bug]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# ReVanced bug report
|
||||||
|
|
||||||
|
Important to note that your issue may have already been reported before. Please check for existing issues [here](https://github.com/revanced/revanced-patches/labels/bug).
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: Type
|
||||||
|
options:
|
||||||
|
- Error while patching
|
||||||
|
- Error at runtime
|
||||||
|
- Cosmetic
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Bug description
|
||||||
|
description: How did you find the bug? Any additional details that might help?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Add the steps to reproduce this bug including your environment.
|
||||||
|
placeholder: Step 1. Download some files. Step 2. ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Relevant log output
|
||||||
|
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Screenshots or videos
|
||||||
|
description: Add screenshots or videos that show the bug here.
|
||||||
|
placeholder: Drag and drop the screenshots/videos into this box.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Solution
|
||||||
|
description: If applicable, add a possible solution.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add additional context here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
24
.github/ISSUE_TEMPLATE/bug-report.md
vendored
24
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Create a bug report on patches
|
|
||||||
title: 'problem: `some-patch`'
|
|
||||||
labels: bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐞 Issue
|
|
||||||
|
|
||||||
<!-- Describe your issue in detail here -->
|
|
||||||
|
|
||||||
## ⚙ Reproduce
|
|
||||||
|
|
||||||
<!-- Include your environment and steps to reproduce the issue as detailed as possible -->
|
|
||||||
|
|
||||||
## 🛠 Solution
|
|
||||||
|
|
||||||
<!-- If applicable, add a possible solution -->
|
|
||||||
|
|
||||||
## ⚠ Additional context
|
|
||||||
|
|
||||||
<!-- Add any other context about the problem here -->
|
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: 📃 Documentation
|
||||||
|
url: https://github.com/revanced/revanced-documentation/
|
||||||
|
about: Don't know how or where to start? Check out our documentation!
|
||||||
|
- name: 🗨 Discussions
|
||||||
|
url: https://github.com/revanced/revanced-suggestions/discussions
|
||||||
|
about: Got something you think should change or be added? Search for or start a new discussion!
|
||||||
46
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
Normal file
46
.github/ISSUE_TEMPLATE/feature-issue.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: ⭐ Feature request
|
||||||
|
description: Create a detailed feature request.
|
||||||
|
title: 'feat: <title>'
|
||||||
|
labels: [feature-request]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# ReVanced feature request
|
||||||
|
|
||||||
|
Do not submit requests for patches here. Please submit them [here](https://github.com/orgs/revanced/discussions/categories/patches) instead.
|
||||||
|
Important to note that your feature request may have already been made before. Please check for existing feature requests [here](https://github.com/revanced/revanced-patches/labels/feature-request).
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: Type
|
||||||
|
options:
|
||||||
|
- Functionality
|
||||||
|
- Cosmetic
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Issue
|
||||||
|
description: What is the current problem. Why does it require a feature request?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Feature
|
||||||
|
description: Describe your feature in detail. How does it solve the issue?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Motivation
|
||||||
|
description: Why should your feature should be considered?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add additional context here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Suggest a change to some patch. Do not submit suggestions for patches here.
|
|
||||||
title: 'feat: some feature'
|
|
||||||
labels: feature-request
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐞 Issue
|
|
||||||
|
|
||||||
<!-- Explain here, what the current problem is and why it leads you to request a feature change -->
|
|
||||||
|
|
||||||
## ❗ Solution
|
|
||||||
|
|
||||||
<!-- Explain how your current issue can be solved -->
|
|
||||||
|
|
||||||
## ❓ Motivation
|
|
||||||
|
|
||||||
<!-- Explain why your feature should be considered -->
|
|
||||||
|
|
||||||
## ⚠ Additional context
|
|
||||||
|
|
||||||
<!-- Add any other context or screenshots about the feature request here -->
|
|
||||||
49
CHANGELOG.md
49
CHANGELOG.md
@@ -1,3 +1,52 @@
|
|||||||
|
# [2.26.0](https://github.com/revanced/revanced-patches/compare/v2.25.3...v2.26.0) (2022-07-31)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `ResourceUtils` helper class ([e0e1144](https://github.com/revanced/revanced-patches/commit/e0e11447a7ac184d43c75955854c52c6992ff667))
|
||||||
|
|
||||||
|
## [2.25.3](https://github.com/revanced/revanced-patches/compare/v2.25.2...v2.25.3) (2022-07-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* actually call `VideoInformation.setCurrentVideoId` first ([5c62d0a](https://github.com/revanced/revanced-patches/commit/5c62d0a2e0217de1b9563a41b4e94ed63230440f))
|
||||||
|
|
||||||
|
## [2.25.2](https://github.com/revanced/revanced-patches/compare/v2.25.1...v2.25.2) (2022-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* rename `default-video-quality` to `remember-video-quality` ([7f6cdfd](https://github.com/revanced/revanced-patches/commit/7f6cdfd7c2b5e72742bbb92e4d584f722cb82cae))
|
||||||
|
|
||||||
|
## [2.25.1](https://github.com/revanced/revanced-patches/compare/v2.25.0...v2.25.1) (2022-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* `default-video-quality` patch crashing ([#227](https://github.com/revanced/revanced-patches/issues/227)) ([379327a](https://github.com/revanced/revanced-patches/commit/379327a6b2325ef93c7107472343dd9fd85a0f56))
|
||||||
|
|
||||||
|
# [2.25.0](https://github.com/revanced/revanced-patches/compare/v2.24.0...v2.25.0) (2022-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `general-reddit-ads` patch ([#235](https://github.com/revanced/revanced-patches/issues/235)) ([d63c016](https://github.com/revanced/revanced-patches/commit/d63c016d38d2a5b1d152abccdb582990987a1911))
|
||||||
|
|
||||||
|
# [2.24.0](https://github.com/revanced/revanced-patches/compare/v2.23.0...v2.24.0) (2022-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `music-microg-support` patch ([#208](https://github.com/revanced/revanced-patches/issues/208)) ([50863e9](https://github.com/revanced/revanced-patches/commit/50863e97cc8eba7e1ad6d11b4821baa45fdd29c4))
|
||||||
|
|
||||||
|
# [2.23.0](https://github.com/revanced/revanced-patches/compare/v2.22.2...v2.23.0) (2022-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* bump compatibility of YouTube Music patches to v5.16.51 ([#238](https://github.com/revanced/revanced-patches/issues/238)) ([4fa2a12](https://github.com/revanced/revanced-patches/commit/4fa2a127d715f953a1e4efacaecbc218209a01f3))
|
||||||
|
|
||||||
## [2.22.2](https://github.com/revanced/revanced-patches/compare/v2.22.1...v2.22.2) (2022-07-26)
|
## [2.22.2](https://github.com/revanced/revanced-patches/compare/v2.22.1...v2.22.2) (2022-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
29
README.md
29
README.md
@@ -9,6 +9,15 @@ Official patches by ReVanced
|
|||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `timeline-ads` | Removes ads from the Twitter timeline. | all |
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### 📦 `com.reddit.frontpage`
|
||||||
|
<details>
|
||||||
|
|
||||||
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 📦 `com.google.android.apps.youtube.music`
|
### 📦 `com.google.android.apps.youtube.music`
|
||||||
@@ -16,14 +25,16 @@ Official patches by ReVanced
|
|||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|:--------:|:--------------:|:-----------------:|
|
||||||
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.14.53 |
|
| `minimized-playback-music` | Enables minimized playback on Kids music. | 5.16.51 |
|
||||||
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.14.53 |
|
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.16.51 |
|
||||||
| `compact-header` | Hides the music category bar at the top of the homepage. | 5.14.53 |
|
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.16.51 |
|
||||||
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.14.53 |
|
| `compact-header` | Hides the music category bar at the top of the homepage. | 5.16.51 |
|
||||||
| `background-play` | Enables playing music in the background. | 5.14.53 |
|
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.16.51 |
|
||||||
| `music-video-ads` | Removes ads in the music player. | 5.14.53 |
|
| `background-play` | Enables playing music in the background. | 5.16.51 |
|
||||||
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.14.53 |
|
| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | 5.16.51 |
|
||||||
| `exclusive-audio-playback` | Enables the option to play music without video. | 5.14.53 |
|
| `music-video-ads` | Removes ads in the music player. | 5.16.51 |
|
||||||
|
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.16.51 |
|
||||||
|
| `exclusive-audio-playback` | Enables the option to play music without video. | 5.16.51 |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### 📦 `com.google.android.youtube`
|
### 📦 `com.google.android.youtube`
|
||||||
@@ -31,6 +42,7 @@ Official patches by ReVanced
|
|||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `swipe-controls` | Adds volume and brightness swipe controls. | 17.29.34 |
|
||||||
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.29.34 |
|
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.29.34 |
|
||||||
| `minimized-playback` | Enables minimized and background playback. | 17.29.34 |
|
| `minimized-playback` | Enables minimized and background playback. | 17.29.34 |
|
||||||
| `amoled` | Enables pure black theme. | 17.29.34 |
|
| `amoled` | Enables pure black theme. | 17.29.34 |
|
||||||
@@ -52,6 +64,7 @@ Official patches by ReVanced
|
|||||||
| `enable-debugging` | Enables app debugging by patching the manifest file. | all |
|
| `enable-debugging` | Enables app debugging by patching the manifest file. | all |
|
||||||
| `custom-playback-speed` | Adds more video playback speed options. | 17.29.34 |
|
| `custom-playback-speed` | Adds more video playback speed options. | 17.29.34 |
|
||||||
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.29.34 |
|
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.29.34 |
|
||||||
|
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 17.29.34 |
|
||||||
| `video-ads` | Removes ads in the video player. | 17.29.34 |
|
| `video-ads` | Removes ads in the video player. | 17.29.34 |
|
||||||
| `general-ads` | Removes general ads. | 17.29.34 |
|
| `general-ads` | Removes general ads. | 17.29.34 |
|
||||||
| `hide-infocard-suggestions` | Hides infocards in videos. | 17.29.34 |
|
| `hide-infocard-suggestions` | Hides infocards in videos. | 17.29.34 |
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 2.22.2
|
version = 2.26.0
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ object Generator {
|
|||||||
|
|
||||||
bundle.map {
|
bundle.map {
|
||||||
val packageName = it.compatiblePackages?.first()?.name!!
|
val packageName = it.compatiblePackages?.first()?.name!!
|
||||||
packages.getOrElse(packageName) { packages.put(packageName, mutableListOf()) }?.add(it)
|
if (!packages.contains(packageName)) {
|
||||||
|
packages[packageName] = mutableListOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
packages[packageName]?.add(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pkg in packages) {
|
for (pkg in packages) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class MusicMicroGPatchCompatibility
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
@Name("google-play-utility-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lnuv;", "b"
|
||||||
|
)
|
||||||
|
@DirectPatternScanMethod
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object GooglePlayUtilityFingerprint : MethodFingerprint(
|
||||||
|
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), null, listOf("This should never happen.", "MetadataValueReader", "GooglePlayServicesUtil", "com.android.vending", "android.hardware.type.embedded")
|
||||||
|
)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
|
||||||
|
@Name("google-play-prime-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lrwi;", "a"
|
||||||
|
)
|
||||||
|
@DirectPatternScanMethod
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object PrimeFingerprint : MethodFingerprint(
|
||||||
|
null, null, null, null, listOf("com.google.android.GoogleCamera", "com.android.vending")
|
||||||
|
)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
@Name("google-play-service-checker-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Lnuv;", "d"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object ServiceCheckFingerprint : MethodFingerprint(
|
||||||
|
"V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), null, listOf("Google Play Services not available")
|
||||||
|
)
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.patch.bytecode
|
||||||
|
|
||||||
|
import app.revanced.extensions.equalsAny
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch
|
||||||
|
import app.revanced.patches.youtube.misc.microg.patch.resource.enum.StringReplaceMode
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.fingerprints.*
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Dependencies([MusicMicroGResourcePatch::class])
|
||||||
|
@Name("music-microg-support")
|
||||||
|
@Description("Allows YouTube Music ReVanced to run without root and under a different package name.")
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class MusicMicroGBytecodePatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
ServiceCheckFingerprint,
|
||||||
|
GooglePlayUtilityFingerprint,
|
||||||
|
PrimeFingerprint,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
disablePlayServiceChecks()
|
||||||
|
data.classes.forEach { classDef ->
|
||||||
|
var proxiedClass: MutableClass? = null
|
||||||
|
|
||||||
|
classDef.methods.forEach methodLoop@{ method ->
|
||||||
|
val implementation = method.implementation ?: return@methodLoop
|
||||||
|
|
||||||
|
var proxiedImplementation: MutableMethodImplementation? = null
|
||||||
|
|
||||||
|
implementation.instructions.forEachIndexed { i, instruction ->
|
||||||
|
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
||||||
|
|
||||||
|
val stringValue = ((instruction as Instruction21c).reference as StringReference).string
|
||||||
|
|
||||||
|
val replaceMode = if (stringValue.equalsAny(
|
||||||
|
"com.google.android.gms",
|
||||||
|
"com.google.android.gms.chimera",
|
||||||
|
"com.google.android.c2dm.intent.REGISTER",
|
||||||
|
"com.google.android.c2dm.permission.SEND",
|
||||||
|
"com.google.iid.TOKEN_REQUEST",
|
||||||
|
"com.google",
|
||||||
|
"com.google.android.gms.chimera.GmsIntentOperationService",
|
||||||
|
"com.google.android.gms.phenotype.internal.IPhenotypeCallbacks",
|
||||||
|
"com.google.android.gms.phenotype.internal.IPhenotypeService",
|
||||||
|
"com.google.android.gms.phenotype.service.START",
|
||||||
|
"com.google.android.gms.phenotype.PACKAGE_NAME",
|
||||||
|
"com.google.android.gms.phenotype.UPDATE",
|
||||||
|
"com.google.android.gms.phenotype",
|
||||||
|
"com.google.android.gms.auth.accounts",
|
||||||
|
"com.google.android.c2dm.intent.REGISTRATION",
|
||||||
|
"com.google.android.gsf.action.GET_GLS",
|
||||||
|
"com.google.android.gsf.login",
|
||||||
|
"content://com.google.settings/partner",
|
||||||
|
"content://com.google.android.gms.phenotype/",
|
||||||
|
"content://com.google.android.gsf.gservices",
|
||||||
|
"content://com.google.android.gsf.gservices/prefix",
|
||||||
|
"com.google.android.c2dm.intent.RECEIVE"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringReplaceMode.REPLACE_WITH_MICROG
|
||||||
|
} else if (stringValue.equalsAny(
|
||||||
|
"com.google.android.apps.youtube.music.SuggestionsProvider", "com.google.android.apps.youtube.music.fileprovider"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StringReplaceMode.REPLACE_WITH_REVANCED
|
||||||
|
} else {
|
||||||
|
StringReplaceMode.DO_NOT_REPLACE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replaceMode != StringReplaceMode.DO_NOT_REPLACE) {
|
||||||
|
if (proxiedClass == null) {
|
||||||
|
proxiedClass = data.proxy(classDef).resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxiedImplementation == null) {
|
||||||
|
proxiedImplementation = proxiedClass!!.methods.first {
|
||||||
|
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
||||||
|
}.implementation!!
|
||||||
|
}
|
||||||
|
|
||||||
|
val newString = if (replaceMode == StringReplaceMode.REPLACE_WITH_REVANCED) stringValue.replace(
|
||||||
|
"com.google.android.apps.youtube.music", REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
)
|
||||||
|
else stringValue.replace("com.google", BASE_MICROG_PACKAGE_NAME)
|
||||||
|
|
||||||
|
proxiedImplementation!!.replaceInstruction(
|
||||||
|
i, BuilderInstruction21c(
|
||||||
|
Opcode.CONST_STRING, instruction.registerA, ImmutableStringReference(newString)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun disablePlayServiceChecks() {
|
||||||
|
listOf(
|
||||||
|
ServiceCheckFingerprint,
|
||||||
|
GooglePlayUtilityFingerprint,
|
||||||
|
).forEach { fingerprint ->
|
||||||
|
val result = fingerprint.result!!
|
||||||
|
val stringInstructions = when (result.method.returnType.first()) {
|
||||||
|
'V' -> "return-void"
|
||||||
|
'I' -> """
|
||||||
|
const/4 v0, 0x0
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
|
||||||
|
else -> throw Exception("This case should never happen.")
|
||||||
|
}
|
||||||
|
result.mutableMethod.addInstructions(
|
||||||
|
0, stringInstructions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val primeMethod = PrimeFingerprint.result!!.mutableMethod
|
||||||
|
val implementation = primeMethod.implementation!!
|
||||||
|
|
||||||
|
var register = 2
|
||||||
|
val index = implementation.instructions.indexOfFirst {
|
||||||
|
if (it.opcode != Opcode.CONST_STRING) return@indexOfFirst false
|
||||||
|
|
||||||
|
val instructionString = ((it as Instruction21c).reference as StringReference).string
|
||||||
|
if (instructionString != "com.google.android.apps.youtube.music") return@indexOfFirst false
|
||||||
|
|
||||||
|
register = it.registerA
|
||||||
|
return@indexOfFirst true
|
||||||
|
}
|
||||||
|
|
||||||
|
primeMethod.replaceInstruction(
|
||||||
|
index, "const-string v$register, \"$REVANCED_MUSIC_PACKAGE_NAME\""
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.patch.resource
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.ResourceData
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.impl.ResourcePatch
|
||||||
|
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME
|
||||||
|
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
|
||||||
|
|
||||||
|
@Name("music-microg-resource-patch")
|
||||||
|
@Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.")
|
||||||
|
@MusicMicroGPatchCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class MusicMicroGResourcePatch : ResourcePatch() {
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
|
||||||
|
val manifest = data["AndroidManifest.xml"].readText()
|
||||||
|
|
||||||
|
data["AndroidManifest.xml"].writeText(
|
||||||
|
manifest.replace(
|
||||||
|
"package=\"com.google.android.apps.youtube.music", "package=\"$REVANCED_MUSIC_PACKAGE_NAME"
|
||||||
|
).replace(
|
||||||
|
"android:label=\"@string/app_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
|
||||||
|
).replace(
|
||||||
|
"android:label=\"@string/app_launcher_name", "android:label=\"$REVANCED_MUSIC_APP_NAME"
|
||||||
|
).replace(
|
||||||
|
"android:authorities=\"com.google.android.apps.youtube.music", "android:authorities=\"$REVANCED_MUSIC_PACKAGE_NAME"
|
||||||
|
).replace(
|
||||||
|
"com.google.android.apps.youtube.music.permission.C2D_MESSAGE", "$REVANCED_MUSIC_PACKAGE_NAME.permission.C2D_MESSAGE"
|
||||||
|
).replace(
|
||||||
|
"com.google.android.c2dm", "$BASE_MICROG_PACKAGE_NAME.android.c2dm"
|
||||||
|
).replace(
|
||||||
|
"</queries>", "<package android:name=\"$BASE_MICROG_PACKAGE_NAME.android.gms\"/></queries>"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package app.revanced.patches.music.misc.microg.shared
|
||||||
|
|
||||||
|
object Constants {
|
||||||
|
internal const val BASE_MICROG_PACKAGE_NAME = "com.mgoogle"
|
||||||
|
internal const val REVANCED_MUSIC_APP_NAME = "YouTube Music ReVanced"
|
||||||
|
internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music"
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.apps.youtube.music", arrayOf("5.14.53")
|
"com.google.android.apps.youtube.music", arrayOf("5.14.53", "5.16.51")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package app.revanced.patches.reddit.ad.general.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.reddit.frontpage", arrayOf()
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class GeneralAdsCompatibility
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package app.revanced.patches.reddit.ad.general.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patches.reddit.ad.general.annotations.GeneralAdsCompatibility
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||||
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableStringReference
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("general-reddit-ads")
|
||||||
|
@Description("Removes general ads from the Reddit frontpage and subreddits.")
|
||||||
|
@GeneralAdsCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class GeneralAdsPatch : BytecodePatch() {
|
||||||
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
data.classes.forEach { classDef ->
|
||||||
|
classDef.methods.forEach methodLoop@{ method ->
|
||||||
|
val implementation = method.implementation ?: return@methodLoop
|
||||||
|
|
||||||
|
implementation.instructions.forEachIndexed { i, instruction ->
|
||||||
|
if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed
|
||||||
|
if (((instruction as ReferenceInstruction).reference as StringReference).string != "AdPost") return@forEachIndexed
|
||||||
|
|
||||||
|
val proxiedClass = data.proxy(classDef).resolve()
|
||||||
|
|
||||||
|
val proxiedImplementation = proxiedClass.methods.first {
|
||||||
|
it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes)
|
||||||
|
}.implementation!!
|
||||||
|
|
||||||
|
var newString = "AdPost1"
|
||||||
|
if (proxiedImplementation.instructions[i - 1].opcode == Opcode.CONST_STRING) {
|
||||||
|
newString = "SubredditPost"
|
||||||
|
}
|
||||||
|
proxiedImplementation.replaceInstruction(
|
||||||
|
i, BuilderInstruction21c(
|
||||||
|
Opcode.CONST_STRING, (proxiedImplementation.instructions[i] as BuilderInstruction21c).registerA, ImmutableStringReference(newString)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
|
|||||||
|
|
||||||
@Compatibility(
|
@Compatibility(
|
||||||
[Package(
|
[Package(
|
||||||
"com.google.android.youtube", arrayOf("17.22.36", "17.24.35", "17.26.35", "17.27.39")
|
"com.google.android.youtube", arrayOf("17.22.36", "17.24.35", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ package app.revanced.patches.youtube.misc.quality.fingerprints
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import app.revanced.patches.youtube.misc.quality.annotations.DefaultVideoQualityCompatibility
|
import app.revanced.patches.youtube.misc.quality.annotations.DefaultVideoQualityCompatibility
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
@Name("video-quality-setter-fingerprint")
|
@Name("video-quality-setter-fingerprint")
|
||||||
@MatchingMethod(
|
@MatchingMethod(
|
||||||
"Lkec", "a"
|
"Lkec;", "a"
|
||||||
)
|
)
|
||||||
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
|
@DirectPatternScanMethod
|
||||||
@DefaultVideoQualityCompatibility
|
@DefaultVideoQualityCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object VideoQualitySetterFingerprint : MethodFingerprint(
|
object VideoQualitySetterFingerprint : MethodFingerprint(
|
||||||
|
|||||||
@@ -1,80 +1,69 @@
|
|||||||
package app.revanced.patches.youtube.misc.quality.patch
|
package app.revanced.patches.youtube.misc.quality.patch
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
import app.revanced.patcher.extensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.annotations.Dependencies
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.quality.annotations.DefaultVideoQualityCompatibility
|
import app.revanced.patches.youtube.misc.quality.annotations.DefaultVideoQualityCompatibility
|
||||||
import app.revanced.patches.youtube.misc.quality.fingerprints.VideoQualityReferenceFingerprint
|
import app.revanced.patches.youtube.misc.quality.fingerprints.VideoQualityReferenceFingerprint
|
||||||
import app.revanced.patches.youtube.misc.quality.fingerprints.VideoQualitySetterFingerprint
|
import app.revanced.patches.youtube.misc.quality.fingerprints.VideoQualitySetterFingerprint
|
||||||
import app.revanced.patches.youtube.misc.quality.fingerprints.VideoUserQualityChangeFingerprint
|
import app.revanced.patches.youtube.misc.quality.fingerprints.VideoUserQualityChangeFingerprint
|
||||||
import app.revanced.patches.youtube.misc.videoid.fingerprint.VideoIdFingerprint
|
import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
@Dependencies(
|
@Patch
|
||||||
dependencies = [IntegrationsPatch::class]
|
@Dependencies([IntegrationsPatch::class, VideoIdPatch::class])
|
||||||
)
|
@Name("remember-video-quality")
|
||||||
@Name("default-video-quality")
|
@Description("Adds the ability to remember the video quality you chose in the video quality flyout.")
|
||||||
@Description("Adds the ability to select preferred video quality.")
|
@DefaultVideoQualityCompatibility
|
||||||
@DefaultVideoQualityCompatibility
|
@Version("0.0.1")
|
||||||
@Version("0.0.1")
|
class RememberVideoQualityPatch : BytecodePatch(
|
||||||
class DefaultVideoQualityPatch : BytecodePatch(
|
listOf(
|
||||||
listOf(
|
VideoQualitySetterFingerprint
|
||||||
VideoQualitySetterFingerprint,
|
)
|
||||||
VideoIdFingerprint
|
) {
|
||||||
)
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
val setterMethod = VideoQualitySetterFingerprint.result!!
|
||||||
) {
|
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
VideoUserQualityChangeFingerprint.resolve(data, setterMethod.classDef)
|
||||||
val offset = 4
|
val userQualityMethod = VideoUserQualityChangeFingerprint.result!!
|
||||||
val setterMethod = VideoQualitySetterFingerprint.result!!
|
|
||||||
|
VideoQualityReferenceFingerprint.resolve(data, setterMethod.classDef)
|
||||||
VideoUserQualityChangeFingerprint.resolve(data, setterMethod.classDef)
|
val qualityFieldReference =
|
||||||
val userQualityMethod = VideoUserQualityChangeFingerprint.result!!
|
VideoQualityReferenceFingerprint.result!!.method.let { method ->
|
||||||
|
(method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
|
||||||
VideoQualityReferenceFingerprint.resolve(data, setterMethod.classDef)
|
}
|
||||||
val qualityFieldReference =
|
|
||||||
VideoQualityReferenceFingerprint.result!!.method.let { method ->
|
VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/VideoQualityPatch;->newVideoStarted(Ljava/lang/String;)V")
|
||||||
(method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
|
|
||||||
}
|
val qIndexMethodName =
|
||||||
|
data.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
|
||||||
val qIndexMethodName =
|
|
||||||
data.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
|
setterMethod.mutableMethod.addInstructions(
|
||||||
|
0,
|
||||||
setterMethod.mutableMethod.addInstructions(
|
"""
|
||||||
0,
|
iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
|
||||||
"""
|
const-string v1, "$qIndexMethodName"
|
||||||
iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
|
invoke-static {p1, p2, v0, v1}, Lapp/revanced/integrations/patches/VideoQualityPatch;->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
|
||||||
const-string v1, "$qIndexMethodName"
|
move-result p2
|
||||||
invoke-static {p1, p2, v0, v1}, Lapp/revanced/integrations/patches/VideoQualityPatch;->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
|
""",
|
||||||
move-result p2
|
)
|
||||||
""",
|
|
||||||
)
|
userQualityMethod.mutableMethod.addInstruction(
|
||||||
|
0,
|
||||||
val newVideoMethod = VideoIdFingerprint.result!!
|
"invoke-static {p3}, Lapp/revanced/integrations/patches/VideoQualityPatch;->userChangedQuality(I)V"
|
||||||
val newVideoIndex = newVideoMethod.patternScanResult!!.endIndex + offset
|
)
|
||||||
newVideoMethod.mutableMethod.addInstructions(
|
|
||||||
newVideoIndex, """
|
return PatchResultSuccess()
|
||||||
const/4 v6, 0x1
|
}
|
||||||
invoke-static {v6}, Lapp/revanced/integrations/utils/ReVancedUtils;->setNewVideo(Z)V
|
}
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
userQualityMethod.mutableMethod.addInstruction(
|
|
||||||
0,
|
|
||||||
"invoke-static {p3}, Lapp/revanced/integrations/patches/VideoQualityPatch;->userChangedQuality(I)V"
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -35,15 +35,18 @@ class VideoIdPatch : BytecodePatch(
|
|||||||
|
|
||||||
injectCall("Lapp/revanced/integrations/videoplayer/VideoInformation;->setCurrentVideoId(Ljava/lang/String;)V")
|
injectCall("Lapp/revanced/integrations/videoplayer/VideoInformation;->setCurrentVideoId(Ljava/lang/String;)V")
|
||||||
|
|
||||||
|
offset++ // offset so setCurrentVideoId is called before any injected call
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private lateinit var result: MethodFingerprintResult
|
|
||||||
private var videoIdRegister: Int = 0
|
|
||||||
private lateinit var insertMethod: MutableMethod
|
|
||||||
private var offset = 2
|
private var offset = 2
|
||||||
|
|
||||||
|
private var videoIdRegister: Int = 0
|
||||||
|
private lateinit var result: MethodFingerprintResult
|
||||||
|
private lateinit var insertMethod: MutableMethod
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||||
@@ -52,10 +55,9 @@ class VideoIdPatch : BytecodePatch(
|
|||||||
methodDescriptor: String
|
methodDescriptor: String
|
||||||
) {
|
) {
|
||||||
insertMethod.addInstructions(
|
insertMethod.addInstructions(
|
||||||
result.patternScanResult!!.endIndex + offset, // after the move-result-object
|
result.patternScanResult!!.endIndex + offset, // move-result-object offset
|
||||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||||
)
|
)
|
||||||
offset++ // so additional instructions get added later
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt
Normal file
75
src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
package app.revanced.util.resources
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.impl.DomFileEditor
|
||||||
|
import app.revanced.patcher.data.impl.ResourceData
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.nio.file.Files
|
||||||
|
|
||||||
|
internal object ResourceUtils {
|
||||||
|
/**
|
||||||
|
* Copy resources from the current class loader to the resource directory.
|
||||||
|
* @param sourceResourceDirectory The source resource directory name.
|
||||||
|
* @param resources The resources to copy.
|
||||||
|
*/
|
||||||
|
internal fun ResourceData.copyResources(sourceResourceDirectory: String, vararg resources: ResourceGroup) {
|
||||||
|
val classLoader = ResourceUtils.javaClass.classLoader
|
||||||
|
val targetResourceDirectory = this["res"]
|
||||||
|
|
||||||
|
for (resourceGroup in resources) {
|
||||||
|
resourceGroup.resources.forEach { resource ->
|
||||||
|
val resourceFile = "${resourceGroup.resourceDirectoryName}/$resource"
|
||||||
|
Files.copy(
|
||||||
|
classLoader.getResourceAsStream("$sourceResourceDirectory/$resourceFile")!!,
|
||||||
|
targetResourceDirectory.resolve(resourceFile).toPath()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource names mapped to their corresponding resource data.
|
||||||
|
* @param resourceDirectoryName The name of the directory of the resource.
|
||||||
|
* @param resources A list of resource names.
|
||||||
|
*/
|
||||||
|
internal class ResourceGroup(val resourceDirectoryName: String, vararg val resources: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy resources from the current class loader to the resource directory.
|
||||||
|
* @param resourceDirectory The directory of the resource.
|
||||||
|
* @param targetResource The target resource.
|
||||||
|
* @param elementTag The element to copy.
|
||||||
|
*/
|
||||||
|
internal fun ResourceData.copyXmlNode(resourceDirectory: String, targetResource: String, elementTag: String) {
|
||||||
|
val stringsResourceInputStream = ResourceUtils.javaClass.classLoader.getResourceAsStream("$resourceDirectory/$targetResource")!!
|
||||||
|
|
||||||
|
// Copy nodes from the resources node to the real resource node
|
||||||
|
elementTag.copyXmlNode(
|
||||||
|
this.xmlEditor[stringsResourceInputStream, OutputStream.nullOutputStream()],
|
||||||
|
this.xmlEditor["res/$targetResource"]
|
||||||
|
).close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the specified node of the source [DomFileEditor] to the target [DomFileEditor].
|
||||||
|
* @param source the source [DomFileEditor].
|
||||||
|
* @param target the target [DomFileEditor]-
|
||||||
|
* @return AutoCloseable that closes the target [DomFileEditor]s.
|
||||||
|
*/
|
||||||
|
internal fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable {
|
||||||
|
val hostNodes = source.file.getElementsByTagName(this).item(0).childNodes
|
||||||
|
|
||||||
|
val destinationResourceFile = target.file
|
||||||
|
val destinationNode = destinationResourceFile.getElementsByTagName(this).item(0)
|
||||||
|
|
||||||
|
for (index in 0 until hostNodes.length) {
|
||||||
|
val node = hostNodes.item(index).cloneNode(true)
|
||||||
|
destinationResourceFile.adoptNode(node)
|
||||||
|
destinationNode.appendChild(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return AutoCloseable {
|
||||||
|
source.close()
|
||||||
|
target.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user