mirror of
https://github.com/revanced/revanced-patches
synced 2024-12-04 19:12:54 +01:00
chore: merge branch dev
to main
(#1755)
This commit is contained in:
commit
129701e9f0
7
.github/workflows/pull_request.yml
vendored
7
.github/workflows/pull_request.yml
vendored
@ -21,5 +21,10 @@ jobs:
|
||||
with:
|
||||
destination_branch: 'main'
|
||||
pr_title: 'chore: ${{ env.MESSAGE }}'
|
||||
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
|
||||
pr_body: |
|
||||
This pull request will ${{ env.MESSAGE }}.
|
||||
|
||||
## Dependencies before merge
|
||||
|
||||
- [] https://github.com/revanced/revanced-integrations
|
||||
pr_draft: true
|
||||
|
54
CHANGELOG.md
54
CHANGELOG.md
@ -1,3 +1,57 @@
|
||||
# [2.167.0-dev.6](https://github.com/revanced/revanced-patches/compare/v2.167.0-dev.5...v2.167.0-dev.6) (2023-03-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **twitter:** remove `monochrome-icon` patch ([#1786](https://github.com/revanced/revanced-patches/issues/1786)) ([b8bf804](https://github.com/revanced/revanced-patches/commit/b8bf804835e75c9f2c8453c8ce22cfd8d17318ce))
|
||||
|
||||
# [2.167.0-dev.5](https://github.com/revanced/revanced-patches/compare/v2.167.0-dev.4...v2.167.0-dev.5) (2023-03-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **reddit:** bump compatibility to `2023.10.0` ([#1772](https://github.com/revanced/revanced-patches/issues/1772)) ([f95ab6e](https://github.com/revanced/revanced-patches/commit/f95ab6e13e70667fdffe479b7292112244e6bb9e))
|
||||
|
||||
# [2.167.0-dev.4](https://github.com/revanced/revanced-patches/compare/v2.167.0-dev.3...v2.167.0-dev.4) (2023-03-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/sponsorblock:** fix segments not skipping during background play ([#1765](https://github.com/revanced/revanced-patches/issues/1765)) ([7620ea1](https://github.com/revanced/revanced-patches/commit/7620ea1752406d703deb15aa0267d4572b1b171a))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* `export-all-activities` patch ([#1751](https://github.com/revanced/revanced-patches/issues/1751)) ([aad6e05](https://github.com/revanced/revanced-patches/commit/aad6e055380f91462d94fc96c4ec17a27e283c64))
|
||||
|
||||
# [2.167.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.167.0-dev.2...v2.167.0-dev.3) (2023-03-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/remember-playback-speed:** allow to not remember playback speed ([#1762](https://github.com/revanced/revanced-patches/issues/1762)) ([49ec3e8](https://github.com/revanced/revanced-patches/commit/49ec3e83f18ec4eb180d220c5a7015f8e4feb3a7))
|
||||
|
||||
# [2.167.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.167.0-dev.1...v2.167.0-dev.2) (2023-03-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **youtube/microg-support:** do not depend on `spoof-signature-verification` patch ([af4e765](https://github.com/revanced/revanced-patches/commit/af4e765ca87c6c979e95bc274b32c764a0a32a88))
|
||||
|
||||
# [2.167.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.166.1-dev.1...v2.167.0-dev.1) (2023-03-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **youtube/spoof-signature-verification:** automatic signature spoofing ([f1395f4](https://github.com/revanced/revanced-patches/commit/f1395f49fae1c0a00de074d58fa7d81f562d3009))
|
||||
|
||||
## [2.166.1-dev.1](https://github.com/revanced/revanced-patches/compare/v2.166.0...v2.166.1-dev.1) (2023-03-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **youtube/spoof-signature-verification:** fix audio during home feed video playback ([#1754](https://github.com/revanced/revanced-patches/issues/1754)) ([7dd067b](https://github.com/revanced/revanced-patches/commit/7dd067b0e96679fe653c9796bef31d743287b2d0))
|
||||
|
||||
# [2.166.0](https://github.com/revanced/revanced-patches/compare/v2.165.1...v2.166.0) (2023-03-14)
|
||||
|
||||
|
||||
|
57
README.md
57
README.md
@ -51,7 +51,7 @@ 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.05.40 |
|
||||
| `open-links-externally` | Open links outside of the app directly in your browser. | 18.05.40 |
|
||||
| `premium-heading` | Shows premium branding on the home screen. | all |
|
||||
| `remember-playback-rate` | Adds the ability to remember the playback rate you chose in the video playback rate flyout. | 18.05.40 |
|
||||
| `remember-playback-speed` | Adds the ability to remember the playback speed you chose in the video playback speed flyout. | 18.05.40 |
|
||||
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.05.40 |
|
||||
| `remove-player-button-background` | Removes the background from the video player buttons. | 18.05.40 |
|
||||
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.05.40 |
|
||||
@ -136,7 +136,6 @@ The official Patch bundle provided by ReVanced and the community.
|
||||
| `hide-ads` | Hides ads. | all |
|
||||
| `hide-recommended-users` | Hides recommended users. | all |
|
||||
| `hide-views-stats` | Hides the view stats under tweets. | 9.71.0-release.0 |
|
||||
| `monochrome-icon` | Adds a monochrome icon. | all |
|
||||
</details>
|
||||
|
||||
### [📦 `com.spotify.music`](https://play.google.com/store/apps/details?id=com.spotify.music)
|
||||
@ -154,8 +153,8 @@ The official Patch bundle provided by ReVanced and the community.
|
||||
|
||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||
|:--------:|:--------------:|:-----------------:|
|
||||
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2023.09.1 |
|
||||
| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | 2023.09.1 |
|
||||
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2023.10.0 |
|
||||
| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | 2023.10.0 |
|
||||
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
|
||||
</details>
|
||||
|
||||
@ -290,6 +289,22 @@ The official Patch bundle provided by ReVanced and the community.
|
||||
| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | 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.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>
|
||||
|
||||
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
|
||||
<details>
|
||||
|
||||
@ -298,6 +313,14 @@ The official Patch bundle provided by ReVanced and the community.
|
||||
| `unlock-pro` | Unlocks all pro features. | all |
|
||||
</details>
|
||||
|
||||
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
|
||||
<details>
|
||||
|
||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||
|:--------:|:--------------:|:-----------------:|
|
||||
| `unlock-pro` | Unlocks all pro features. | all |
|
||||
</details>
|
||||
|
||||
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
|
||||
<details>
|
||||
|
||||
@ -306,36 +329,12 @@ The official Patch bundle provided by ReVanced and the community.
|
||||
| `unlock-pro` | Unlocks pro features. | all |
|
||||
</details>
|
||||
|
||||
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
|
||||
<details>
|
||||
|
||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||
|:--------:|:--------------:|:-----------------:|
|
||||
| `unlock-pro` | Unlocks all 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>
|
||||
|
||||
### [📦 `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>
|
||||
|
||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||
|:--------:|:--------------:|:-----------------:|
|
||||
| `unlock-themes` | Unlocks all themes. | all |
|
||||
| `unlock-themes` | Unlocks all themes that are inaccessible until a certain level is reached. | all |
|
||||
</details>
|
||||
|
||||
### [📦 `net.dinglisch.android.taskerm`](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)
|
||||
|
@ -1,2 +1,2 @@
|
||||
kotlin.code.style = official
|
||||
version = 2.166.0
|
||||
version = 2.167.0-dev.6
|
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,45 @@
|
||||
package app.revanced.patches.all.activity.exportAll.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
|
||||
|
||||
@Patch(false)
|
||||
@Name("export-all-activities")
|
||||
@Description("Makes all app activities exportable.")
|
||||
@Version("0.0.1")
|
||||
class ExportAllActivitiesPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
context.xmlEditor["AndroidManifest.xml"].use { editor ->
|
||||
val document = editor.file
|
||||
val activities = document.getElementsByTagName("activity")
|
||||
|
||||
for(i in 0..activities.length) {
|
||||
activities.item(i)?.apply {
|
||||
val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG)
|
||||
|
||||
if (exportedAttribute != null) {
|
||||
if (exportedAttribute.nodeValue != "true")
|
||||
exportedAttribute.nodeValue = "true"
|
||||
}
|
||||
// Reason why the attribute is added in the case it does not exist:
|
||||
// https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604
|
||||
else document.createAttribute(EXPORTED_FLAG)
|
||||
.apply { value = "true" }
|
||||
.let(attributes::setNamedItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EXPORTED_FLAG = "android:exported"
|
||||
}
|
||||
}
|
@ -12,7 +12,8 @@ import app.revanced.patcher.annotation.Package
|
||||
"2023.07.1",
|
||||
"2023.08.0",
|
||||
"2023.09.0",
|
||||
"2023.09.1"
|
||||
"2023.09.1",
|
||||
"2023.10.0"
|
||||
)
|
||||
)]
|
||||
)
|
||||
|
@ -14,7 +14,8 @@ import app.revanced.patcher.annotation.Package
|
||||
"2023.07.1",
|
||||
"2023.08.0",
|
||||
"2023.09.0",
|
||||
"2023.09.1"
|
||||
"2023.09.1",
|
||||
"2023.10.0"
|
||||
)
|
||||
)]
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ import app.revanced.patches.ticktick.misc.themeunlock.fingerprints.SetThemeFinge
|
||||
|
||||
@Patch
|
||||
@Name("unlock-themes")
|
||||
@Description("Unlocks all themes.")
|
||||
@Description("Unlocks all themes that are inaccessible until a certain level is reached.")
|
||||
@UnlockThemesCompatibility
|
||||
@Version("0.0.1")
|
||||
class UnlockProPatch : BytecodePatch(
|
||||
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.twitter.misc.monochrome.annotations
|
||||
|
||||
import app.revanced.patcher.annotation.Compatibility
|
||||
import app.revanced.patcher.annotation.Package
|
||||
|
||||
@Compatibility([Package("com.twitter.android")])
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class MonochromeIconCompatibility
|
@ -1,55 +0,0 @@
|
||||
package app.revanced.patches.twitter.misc.monochrome.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.PatchResultError
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.twitter.misc.monochrome.annotations.MonochromeIconCompatibility
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.Files
|
||||
|
||||
@Patch
|
||||
@Name("monochrome-icon")
|
||||
@Description("Adds a monochrome icon.")
|
||||
@MonochromeIconCompatibility
|
||||
@Version("0.0.1")
|
||||
class MonochromeIconPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
val resDirectory = context["res"]
|
||||
if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.")
|
||||
|
||||
val mipmapV33Directory = resDirectory.resolve("mipmap-anydpi-v33")
|
||||
if (!mipmapV33Directory.isDirectory) Files.createDirectories(mipmapV33Directory.toPath())
|
||||
|
||||
FileWriter(mipmapV33Directory.resolve("ic_launcher_twitter.xml")).use {
|
||||
it.write(
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||
"<adaptive-icon\n" +
|
||||
" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n" +
|
||||
" <background android:drawable=\"@color/ic_launcher_background\" />\n" +
|
||||
" <foreground android:drawable=\"@mipmap/ic_launcher_twitter_foreground\" />\n" +
|
||||
" <monochrome android:drawable=\"@mipmap/ic_launcher_twitter_foreground\" />\n" +
|
||||
"</adaptive-icon>"
|
||||
)
|
||||
}
|
||||
|
||||
FileWriter(mipmapV33Directory.resolve("ic_launcher_twitter_round.xml")).use {
|
||||
it.write(
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||
"<adaptive-icon\n" +
|
||||
" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n" +
|
||||
" <background android:drawable=\"@color/ic_launcher_background\" />\n" +
|
||||
" <foreground android:drawable=\"@mipmap/ic_launcher_twitter_foreground\" />\n" +
|
||||
" <monochrome android:drawable=\"@mipmap/ic_launcher_twitter_foreground\" />\n" +
|
||||
"</adaptive-icon>"
|
||||
)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -81,7 +81,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
|
||||
/*
|
||||
Set current video id
|
||||
*/
|
||||
VideoIdPatch.injectCall("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
VideoIdPatch.injectCallBackgroundPlay("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
|
||||
/*
|
||||
Seekbar drawing
|
||||
|
@ -0,0 +1,17 @@
|
||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
// Resolves to the method CronetDataSource.open
|
||||
// https://androidx.tech/artifacts/media3/media3-datasource-cronet/1.0.0-alpha03-source/androidx/media3/datasource/cronet/CronetDataSource.java.html
|
||||
object OpenCronetDataSourceFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
),
|
||||
strings = listOf(
|
||||
"err_cleartext_not_permitted",
|
||||
),
|
||||
)
|
@ -11,21 +11,42 @@ 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.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||
import app.revanced.patches.youtube.misc.fix.playback.annotation.ProtobufSpoofCompatibility
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.OpenCronetDataSourceFingerprint
|
||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.ProtobufParameterBuilderFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch
|
||||
@Name("spoof-signature-verification")
|
||||
@Description("Spoofs the client to prevent playback issues.")
|
||||
@ProtobufSpoofCompatibility
|
||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
||||
@Version("0.0.1")
|
||||
class SpoofSignatureVerificationPatch : BytecodePatch(
|
||||
listOf(ProtobufParameterBuilderFingerprint)
|
||||
listOf(
|
||||
ProtobufParameterBuilderFingerprint,
|
||||
OpenCronetDataSourceFingerprint,
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_spoof_signature_verification",
|
||||
StringResource("revanced_spoof_signature_verification_title", "Spoof app signature"),
|
||||
false,
|
||||
StringResource("revanced_spoof_signature_verification_summary_on", "App signature spoofed"),
|
||||
StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed")
|
||||
)
|
||||
)
|
||||
|
||||
// hook parameter
|
||||
ProtobufParameterBuilderFingerprint.result?.let {
|
||||
val setParamMethod = context
|
||||
.toMethodWalker(it.method)
|
||||
@ -33,21 +54,38 @@ class SpoofSignatureVerificationPatch : BytecodePatch(
|
||||
|
||||
setParamMethod.apply {
|
||||
val protobufParameterRegister = 3
|
||||
val parameterValue = "8AEByAMTuAQP" /* Protobuf Parameter of shorts */
|
||||
|
||||
addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-virtual { p$protobufParameterRegister }, Ljava/lang/String;->length()I
|
||||
move-result v0
|
||||
const/16 v1, 0x10
|
||||
if-ge v0, v1, :not_spoof # bypass on feed
|
||||
const-string p$protobufParameterRegister, "$parameterValue"
|
||||
""",
|
||||
listOf(ExternalLabel("not_spoof", instruction(0))))
|
||||
invoke-static {p$protobufParameterRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideProtobufParameter(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object p$protobufParameterRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return ProtobufParameterBuilderFingerprint.toErrorResult()
|
||||
|
||||
// hook video playback result
|
||||
OpenCronetDataSourceFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val getHeadersInstructionIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val responseCodeRegister =
|
||||
(instruction(getHeadersInstructionIndex - 2) as OneRegisterInstruction).registerA
|
||||
|
||||
addInstructions(
|
||||
getHeadersInstructionIndex + 1,
|
||||
"""
|
||||
invoke-static {v$responseCodeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onResponse(I)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
} ?: return OpenCronetDataSourceFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/SpoofSignatureVerificationPatch;"
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,7 @@ import app.revanced.util.microg.MicroGBytecodeHelper
|
||||
[
|
||||
MicroGResourcePatch::class,
|
||||
HideCastButtonPatch::class,
|
||||
ClientSpoofPatch::class,
|
||||
SpoofSignatureVerificationPatch::class
|
||||
ClientSpoofPatch::class
|
||||
]
|
||||
)
|
||||
@Name("microg-support")
|
||||
|
@ -98,7 +98,9 @@ class VideoInformationPatch : BytecodePatch(
|
||||
/*
|
||||
Inject call for video id
|
||||
*/
|
||||
VideoIdPatch.injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||
val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V"
|
||||
VideoIdPatch.injectCall(videoIdMethodDescriptor)
|
||||
VideoIdPatch.injectCallBackgroundPlay(videoIdMethodDescriptor)
|
||||
|
||||
/*
|
||||
Set the video time method
|
||||
|
@ -18,4 +18,4 @@ import app.revanced.patcher.annotation.Package
|
||||
)]
|
||||
)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
internal annotation class RememberPlaybackRateCompatibility
|
||||
internal annotation class RememberPlaybackSpeedCompatibility
|
@ -2,7 +2,7 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object ChangePlaybackRateFragmentStateFingerprint : MethodFingerprint(
|
||||
object ChangePlaybackSpeedFragmentStateFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
|
||||
)
|
@ -2,6 +2,6 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object InitializePlaybackRateValuesFingerprint : MethodFingerprint(
|
||||
object InitializePlaybackSpeedValuesFingerprint : MethodFingerprint(
|
||||
parameters = listOf("[L", "I")
|
||||
)
|
@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object OnPlaybackRateItemClickFingerprint : MethodFingerprint(
|
||||
object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint(
|
||||
customFingerprint = { it.name == "onItemClick" },
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
@ -18,26 +18,108 @@ 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.speed.remember.annotation.RememberPlaybackRateCompatibility
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackRateFragmentStateFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackRateValuesFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackRateItemClickFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.ChangePlaybackSpeedFragmentStateFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.OnPlaybackSpeedItemClickFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
|
||||
@Patch
|
||||
@Name("remember-playback-rate")
|
||||
@Description("Adds the ability to remember the playback rate you chose in the video playback rate flyout.")
|
||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
||||
@RememberPlaybackRateCompatibility
|
||||
@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])
|
||||
@RememberPlaybackSpeedCompatibility
|
||||
@Version("0.0.1")
|
||||
class RememberPlaybackRatePatch : BytecodePatch(
|
||||
listOf(ChangePlaybackRateFragmentStateFingerprint)
|
||||
class RememberPlaybackSpeedPatch : BytecodePatch(
|
||||
listOf(ChangePlaybackSpeedFragmentStateFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_remember_playback_speed_last_selected",
|
||||
StringResource(
|
||||
"revanced_remember_playback_speed_last_selected_title",
|
||||
"Remember playback speed changes"
|
||||
),
|
||||
true,
|
||||
StringResource(
|
||||
"revanced_remember_playback_speed_last_selected_summary_on",
|
||||
"Playback speed changes apply to all videos"
|
||||
),
|
||||
StringResource(
|
||||
"revanced_remember_playback_speed_last_selected_summary_off",
|
||||
"Playback speed changes only apply to the current video"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
context.resolveFingerprints()
|
||||
|
||||
VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V")
|
||||
|
||||
// Set the remembered playback speed.
|
||||
InitializePlaybackSpeedValuesFingerprint.result!!.apply {
|
||||
// Infer everything necessary for setPlaybackSate()
|
||||
|
||||
val playbackHandlerWrapperFieldReference =
|
||||
(object : MethodFingerprint(opcodes = listOf(Opcode.IF_EQZ)) {}).apply {
|
||||
OnPlaybackSpeedItemClickFingerprint.result!!.apply {
|
||||
resolve(
|
||||
context,
|
||||
method,
|
||||
classDef
|
||||
)
|
||||
}
|
||||
}.getReference(-1)
|
||||
val playbackHandlerWrapperImplementorClassReference = OnPlaybackSpeedItemClickFingerprint
|
||||
.getReference(-1)
|
||||
val playbackHandlerFieldReference = OnPlaybackSpeedItemClickFingerprint
|
||||
.getReference()
|
||||
val setPlaybackSpeedMethodReference = OnPlaybackSpeedItemClickFingerprint
|
||||
.getReference(1)
|
||||
|
||||
mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getCurrentPlaybackSpeed()F
|
||||
move-result v0
|
||||
# check if the playback speed is not 1.0x
|
||||
const/high16 v1, 0x3f800000 # 1.0f
|
||||
cmpg-float v1, v0, v1
|
||||
if-eqz v1, :do_not_override
|
||||
|
||||
# invoke setPlaybackSpeed
|
||||
iget-object v1, p0, $playbackHandlerWrapperFieldReference
|
||||
check-cast v1, $playbackHandlerWrapperImplementorClassReference
|
||||
iget-object v2, v1, $playbackHandlerFieldReference
|
||||
invoke-virtual {v2, v0}, $setPlaybackSpeedMethodReference
|
||||
""".trimIndent(),
|
||||
listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0)))
|
||||
)
|
||||
}
|
||||
|
||||
// Remember the selected playback speed.
|
||||
OnPlaybackSpeedItemClickFingerprint.result!!.apply {
|
||||
val setPlaybackSpeedIndex = scanResult.patternScanResult!!.endIndex
|
||||
val selectedPlaybackSpeedRegister =
|
||||
(mutableMethod.instruction(setPlaybackSpeedIndex) as FiveRegisterInstruction).registerD
|
||||
|
||||
mutableMethod.addInstruction(
|
||||
setPlaybackSpeedIndex,
|
||||
"invoke-static { v$selectedPlaybackSpeedRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackRatePatch;"
|
||||
"Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;"
|
||||
|
||||
fun MethodFingerprint.getReference(offsetFromPatternScanResultStartIndex: Int = 0) = this.result!!.let {
|
||||
val referenceInstruction = it.mutableMethod
|
||||
@ -46,92 +128,13 @@ class RememberPlaybackRatePatch : BytecodePatch(
|
||||
}
|
||||
|
||||
fun BytecodeContext.resolveFingerprints() {
|
||||
ChangePlaybackRateFragmentStateFingerprint.result?.also {
|
||||
ChangePlaybackSpeedFragmentStateFingerprint.result?.also {
|
||||
fun MethodFingerprint.resolve() = resolve(this@resolveFingerprints, it.classDef)
|
||||
|
||||
OnPlaybackRateItemClickFingerprint.resolve()
|
||||
InitializePlaybackRateValuesFingerprint.resolve()
|
||||
OnPlaybackSpeedItemClickFingerprint.resolve()
|
||||
InitializePlaybackSpeedValuesFingerprint.resolve()
|
||||
|
||||
} ?: throw ChangePlaybackRateFragmentStateFingerprint.toErrorResult()
|
||||
} ?: throw ChangePlaybackSpeedFragmentStateFingerprint.toErrorResult()
|
||||
}
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
SwitchPreference(
|
||||
"revanced_remember_playback_rate_last_selected",
|
||||
StringResource("revanced_remember_playback_rate_last_selected_title", "Remember playback rate changes"),
|
||||
true,
|
||||
StringResource(
|
||||
"revanced_remember_playback_rate_last_selected_summary_on",
|
||||
"Playback rate changes apply to all videos"
|
||||
),
|
||||
StringResource(
|
||||
"revanced_remember_playback_rate_last_selected_summary_off",
|
||||
"Playback rate changes only apply to the current video"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
context.resolveFingerprints()
|
||||
|
||||
// Set the remembered playback rate.
|
||||
InitializePlaybackRateValuesFingerprint.result!!.apply {
|
||||
// Infer everything necessary for setPlaybackRate()
|
||||
|
||||
val playbackHandlerWrapperFieldReference =
|
||||
(object : MethodFingerprint(opcodes = listOf(Opcode.IF_EQZ)) {}).apply {
|
||||
OnPlaybackRateItemClickFingerprint.result!!.apply {
|
||||
resolve(
|
||||
context,
|
||||
method,
|
||||
classDef
|
||||
)
|
||||
}
|
||||
}.getReference(-1)
|
||||
val playbackHandlerWrapperImplementorClassReference = OnPlaybackRateItemClickFingerprint
|
||||
.getReference(-1)
|
||||
val playbackHandlerFieldReference = OnPlaybackRateItemClickFingerprint
|
||||
.getReference()
|
||||
val setPlaybackRateMethodReference = OnPlaybackRateItemClickFingerprint
|
||||
.getReference(1)
|
||||
|
||||
mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRememberedPlaybackRate()F
|
||||
move-result v0
|
||||
|
||||
# check if the playback rate is below 0 (when a playback rate was never remembered)
|
||||
|
||||
const/4 v1, 0x0
|
||||
cmpg-float v1, v0, v1
|
||||
if-lez v1, :do_not_override
|
||||
|
||||
# invoke setPlaybackRate
|
||||
|
||||
iget-object v1, p0, $playbackHandlerWrapperFieldReference
|
||||
check-cast v1, $playbackHandlerWrapperImplementorClassReference
|
||||
iget-object v2, v1, $playbackHandlerFieldReference
|
||||
invoke-virtual {v2, v0}, $setPlaybackRateMethodReference
|
||||
""".trimIndent(),
|
||||
listOf(ExternalLabel("do_not_override", mutableMethod.instruction(0)))
|
||||
)
|
||||
}
|
||||
|
||||
// Remember the selected playback rate.
|
||||
OnPlaybackRateItemClickFingerprint.result!!.apply {
|
||||
val setPlaybackRateIndex = scanResult.patternScanResult!!.endIndex
|
||||
val selectedPlaybackRateRegister =
|
||||
(mutableMethod.instruction(setPlaybackRateIndex) as FiveRegisterInstruction).registerD
|
||||
|
||||
mutableMethod.addInstruction(
|
||||
setPlaybackRateIndex,
|
||||
"invoke-static { v$selectedPlaybackRateRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->rememberPlaybackRate(F)V"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.misc.video.videoid.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object VideoIdFingerprintBackgroundPlay : MethodFingerprint(
|
||||
returnType = "V",
|
||||
access = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(Opcode.INVOKE_INTERFACE),
|
||||
customFingerprint = {
|
||||
it.definingClass.endsWith("PlaybackLifecycleMonitor;")
|
||||
}
|
||||
)
|
@ -15,6 +15,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.video.videoid.annotation.VideoIdCompatibility
|
||||
import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprint
|
||||
import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("video-id-hook")
|
||||
@ -23,43 +24,79 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@Version("0.0.1")
|
||||
@DependsOn([IntegrationsPatch::class])
|
||||
class VideoIdPatch : BytecodePatch(
|
||||
listOf(VideoIdFingerprint)
|
||||
listOf(VideoIdFingerprint, VideoIdFingerprintBackgroundPlay)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
VideoIdFingerprint.result?.let {
|
||||
val videoIdRegisterInstructionIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
VideoIdFingerprint.result?.let { result ->
|
||||
val videoIdRegisterInstructionIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
with(it.mutableMethod) {
|
||||
insertMethod = this
|
||||
result.mutableMethod.also {
|
||||
insertMethod = it
|
||||
}.apply {
|
||||
videoIdRegister = (instruction(videoIdRegisterInstructionIndex) as OneRegisterInstruction).registerA
|
||||
insertIndex = videoIdRegisterInstructionIndex + 1
|
||||
}
|
||||
} ?: return VideoIdFingerprint.toErrorResult()
|
||||
|
||||
VideoIdFingerprintBackgroundPlay.result?.let { result ->
|
||||
val endIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
result.mutableMethod.also {
|
||||
backgroundPlaybackMethod = it
|
||||
}.apply {
|
||||
backgroundPlaybackVideoIdRegister = (instruction(endIndex + 1) as OneRegisterInstruction).registerA
|
||||
backgroundPlaybackInsertIndex = endIndex + 2
|
||||
}
|
||||
} ?: return VideoIdFingerprintBackgroundPlay.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var videoIdRegister = 0
|
||||
private var insertIndex = 0
|
||||
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
|
||||
private var backgroundPlaybackVideoIdRegister = 0
|
||||
private var backgroundPlaybackInsertIndex = 0
|
||||
private lateinit var backgroundPlaybackMethod: 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.
|
||||
*
|
||||
* Supports all videos (regular videos, Shorts and Stories).
|
||||
*
|
||||
* _Does not function if playing in the background with no video visible_.
|
||||
*
|
||||
* Be aware, this can be called multiple times for the same video id.
|
||||
*
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
// TODO: The order has been proven to not be required, so remove the logic for keeping order.
|
||||
) = insertMethod.addInstructions(
|
||||
// Keep injection calls in the order they're added:
|
||||
// Increment index. So if additional injection calls are added, those calls run after this injection call.
|
||||
insertIndex++,
|
||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate hook that supports only regular videos, but hook supports changing to new video
|
||||
* during background play when no video is visible.
|
||||
*
|
||||
* _Does not support Shorts or Stories_.
|
||||
*
|
||||
* Be aware, the hook can be called multiple times for the same video id.
|
||||
*
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
fun injectCallBackgroundPlay(
|
||||
methodDescriptor: String
|
||||
) = backgroundPlaybackMethod.addInstructions(
|
||||
backgroundPlaybackInsertIndex++, // move-result-object offset
|
||||
"invoke-static {v$backgroundPlaybackVideoIdRegister}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user