chore: merge branch dev
to main
(#2641)
This commit is contained in:
commit
ce420b076e
56
CHANGELOG.md
56
CHANGELOG.md
|
@ -1,3 +1,59 @@
|
||||||
|
# [2.185.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v2.185.0-dev.6...v2.185.0-dev.7) (2023-07-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **YouTube - Spoof client:** show video time and chapters while using seekbar ([#2607](https://github.com/ReVanced/revanced-patches/issues/2607)) ([9546d12](https://github.com/ReVanced/revanced-patches/commit/9546d126430870d1abd8f43bb687b31b9fcb6fb5))
|
||||||
|
|
||||||
|
# [2.185.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v2.185.0-dev.5...v2.185.0-dev.6) (2023-07-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Tiktok - Settings:** bump compatibility ([#2656](https://github.com/ReVanced/revanced-patches/issues/2656)) ([6641356](https://github.com/ReVanced/revanced-patches/commit/6641356d41813a20c77faac67c37ea517690d25b))
|
||||||
|
|
||||||
|
# [2.185.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v2.185.0-dev.4...v2.185.0-dev.5) (2023-07-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Trakt - Unlock pro:** constraint to last known working version ([#2662](https://github.com/ReVanced/revanced-patches/issues/2662)) ([324bbde](https://github.com/ReVanced/revanced-patches/commit/324bbde92a851e855c11f266e92fa14c39d88160))
|
||||||
|
|
||||||
|
# [2.185.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v2.185.0-dev.3...v2.185.0-dev.4) (2023-07-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **TikTok - Show seekbar:** fix seekbar not always showing ([#2660](https://github.com/ReVanced/revanced-patches/issues/2660)) ([f2742f1](https://github.com/ReVanced/revanced-patches/commit/f2742f1ba117809971a10780823fca99c19a4f34))
|
||||||
|
|
||||||
|
# [2.185.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v2.185.0-dev.2...v2.185.0-dev.3) (2023-07-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Sync for Reddit - Disable ads:** fix compatibility with latest version ([1456577](https://github.com/ReVanced/revanced-patches/commit/1456577f11c4a7e49d6c1ba0103b919dc487f4cf))
|
||||||
|
|
||||||
|
# [2.185.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.185.0-dev.1...v2.185.0-dev.2) (2023-07-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* allocate for more than eight `LithoFilter` array items ([#2643](https://github.com/ReVanced/revanced-patches/issues/2643)) ([fc8660b](https://github.com/ReVanced/revanced-patches/commit/fc8660b740bec2747e5f82b7321027bb8a51e0cf))
|
||||||
|
|
||||||
|
# [2.185.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.184.1-dev.1...v2.185.0-dev.1) (2023-07-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **youtube:** rename `video-speed` to `playback-speed` ([#2642](https://github.com/revanced/revanced-patches/issues/2642)) ([77e8639](https://github.com/revanced/revanced-patches/commit/77e8639b71048f2795f8f32fe18d052b335e3ce4))
|
||||||
|
|
||||||
|
## [2.184.1-dev.1](https://github.com/revanced/revanced-patches/compare/v2.184.0...v2.184.1-dev.1) (2023-07-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **youtube/sponsorblock:** fix some segments skipping slightly too late ([#2634](https://github.com/revanced/revanced-patches/issues/2634)) ([3175431](https://github.com/revanced/revanced-patches/commit/31754311870324b1e245b12965d7486878e9eba4))
|
||||||
|
|
||||||
# [2.184.0](https://github.com/revanced/revanced-patches/compare/v2.183.1...v2.184.0) (2023-07-11)
|
# [2.184.0](https://github.com/revanced/revanced-patches/compare/v2.183.1...v2.184.0) (2023-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 2.184.0
|
version = 2.185.0-dev.7
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,11 +1,10 @@
|
||||||
package app.revanced.patches.syncforreddit.detection.piracy.fingerprints
|
package app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.TypeReference
|
|
||||||
|
|
||||||
object PiracyDetectionFingerprint : MethodFingerprint(
|
object PiracyDetectionFingerprint : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
package app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.patch
|
package app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.patch
|
||||||
|
|
||||||
import app.revanced.extensions.toErrorResult
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
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.patches.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint
|
import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint
|
||||||
|
|
||||||
@Description("Disables detection of modified versions.")
|
@Description("Disables detection of modified versions.")
|
||||||
@Version("0.0.1")
|
|
||||||
class DisablePiracyDetectionPatch : BytecodePatch(listOf(PiracyDetectionFingerprint)) {
|
class DisablePiracyDetectionPatch : BytecodePatch(listOf(PiracyDetectionFingerprint)) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
// Do not return an error if the fingerprint is not resolved.
|
||||||
|
// This is fine because new versions of the target app do not need this patch.
|
||||||
PiracyDetectionFingerprint.result?.mutableMethod?.apply {
|
PiracyDetectionFingerprint.result?.mutableMethod?.apply {
|
||||||
addInstruction(
|
addInstruction(
|
||||||
0,
|
0,
|
||||||
|
@ -21,7 +20,7 @@ class DisablePiracyDetectionPatch : BytecodePatch(listOf(PiracyDetectionFingerpr
|
||||||
return-void
|
return-void
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
} ?: return PiracyDetectionFingerprint.toErrorResult()
|
}
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
package app.revanced.patches.tiktok.interaction.seekbar.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import org.jf.dexlib2.AccessFlags
|
|
||||||
|
|
||||||
object AwemeGetVideoControlFingerprint : MethodFingerprint(
|
|
||||||
"L",
|
|
||||||
AccessFlags.PUBLIC.value,
|
|
||||||
customFingerprint = { methodDef, _ ->
|
|
||||||
methodDef.definingClass.endsWith("/Aweme;") && methodDef.name == "getVideoControl"
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package app.revanced.patches.tiktok.interaction.seekbar.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
object SetSeekBarShowTypeFingerprint : MethodFingerprint(
|
||||||
|
strings = listOf(
|
||||||
|
"seekbar show type change, change to:"
|
||||||
|
),
|
||||||
|
)
|
|
@ -6,17 +6,14 @@ import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patches.tiktok.interaction.seekbar.annotations.ShowSeekbarCompatibility
|
import app.revanced.patches.tiktok.interaction.seekbar.annotations.ShowSeekbarCompatibility
|
||||||
import app.revanced.patches.tiktok.interaction.seekbar.fingerprints.AwemeGetVideoControlFingerprint
|
import app.revanced.patches.tiktok.interaction.seekbar.fingerprints.SetSeekBarShowTypeFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.iface.instruction.formats.Instruction22t
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction11n
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction22c
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("Show seekbar")
|
@Name("Show seekbar")
|
||||||
|
@ -25,27 +22,20 @@ import org.jf.dexlib2.builder.instruction.BuilderInstruction22c
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class ShowSeekbarPatch : BytecodePatch(
|
class ShowSeekbarPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
AwemeGetVideoControlFingerprint
|
SetSeekBarShowTypeFingerprint,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
//Get VideoControl FieldReference
|
SetSeekBarShowTypeFingerprint.result?.mutableMethod?.apply {
|
||||||
val videoControl = context.findClass { it.type.endsWith("/VideoControl;") }
|
val typeRegister = getInstruction<Instruction22t>(1).registerB
|
||||||
?: return PatchResultError("Can not find target class")
|
|
||||||
val fieldList = videoControl.immutableClass.fields.associateBy { field -> field.name }
|
|
||||||
|
|
||||||
AwemeGetVideoControlFingerprint.result?.mutableMethod?.implementation?.apply {
|
|
||||||
val ifNullLabel = newLabelForIndex(1)
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
1,
|
0,
|
||||||
listOf(
|
"""
|
||||||
BuilderInstruction11n(Opcode.CONST_4, 1, 1),
|
const/16 v$typeRegister, 0x64
|
||||||
BuilderInstruction21t(Opcode.IF_EQZ, 0, ifNullLabel),
|
"""
|
||||||
BuilderInstruction22c(Opcode.IPUT, 1, 0, fieldList["showProgressBar"]!!),
|
|
||||||
BuilderInstruction22c(Opcode.IPUT, 1, 0, fieldList["draftProgressBar"]!!)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
} ?: return AwemeGetVideoControlFingerprint.toErrorResult()
|
} ?: return SetSeekBarShowTypeFingerprint.toErrorResult()
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package app.revanced.patches.tiktok.misc.settings.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
object AboutPageFingerprint : MethodFingerprint(
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.CONST, // copyrightPolicyLabel resource id
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.CONST_STRING
|
|
||||||
),
|
|
||||||
customFingerprint = { methodDef, _ ->
|
|
||||||
methodDef.definingClass == "Lcom/ss/android/ugc/aweme/setting/page/AboutPage;" &&
|
|
||||||
methodDef.name == "onViewCreated"
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package app.revanced.patches.tiktok.misc.settings.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
object AddSettingsEntryFingerprint : MethodFingerprint(
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST_CLASS,
|
||||||
|
Opcode.APUT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
),
|
||||||
|
customFingerprint = { methodDef, _ ->
|
||||||
|
methodDef.definingClass.endsWith("/SettingNewVersionFragment;") &&
|
||||||
|
methodDef.name == "onViewCreated"
|
||||||
|
}
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package app.revanced.patches.tiktok.misc.settings.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
object SettingsEntryFingerprint : MethodFingerprint(
|
||||||
|
strings = listOf(
|
||||||
|
"pls pass item or extends the EventUnit"
|
||||||
|
)
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package app.revanced.patches.tiktok.misc.settings.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
object SettingsEntryInfoFingerprint : MethodFingerprint(
|
||||||
|
strings = listOf(
|
||||||
|
"ExposeItem(title=",
|
||||||
|
", icon="
|
||||||
|
)
|
||||||
|
)
|
|
@ -1,10 +0,0 @@
|
||||||
package app.revanced.patches.tiktok.misc.settings.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
object SettingsOnViewCreatedFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { methodDef, _ ->
|
|
||||||
methodDef.definingClass.endsWith("/SettingNewVersionFragment;") &&
|
|
||||||
methodDef.name == "onViewCreated"
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -6,24 +6,19 @@ import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.tiktok.misc.settings.annotations.SettingsCompatibility
|
import app.revanced.patches.tiktok.misc.settings.annotations.SettingsCompatibility
|
||||||
import app.revanced.patches.tiktok.misc.settings.fingerprints.AboutPageFingerprint
|
import app.revanced.patches.tiktok.misc.settings.fingerprints.*
|
||||||
import app.revanced.patches.tiktok.misc.settings.fingerprints.AdPersonalizationActivityOnCreateFingerprint
|
|
||||||
import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsOnViewCreatedFingerprint
|
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@DependsOn([IntegrationsPatch::class])
|
@DependsOn([IntegrationsPatch::class])
|
||||||
|
@ -33,65 +28,44 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class SettingsPatch : BytecodePatch(
|
class SettingsPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
AboutPageFingerprint,
|
|
||||||
AdPersonalizationActivityOnCreateFingerprint,
|
AdPersonalizationActivityOnCreateFingerprint,
|
||||||
SettingsOnViewCreatedFingerprint,
|
AddSettingsEntryFingerprint,
|
||||||
|
SettingsEntryFingerprint,
|
||||||
|
SettingsEntryInfoFingerprint,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
SettingsOnViewCreatedFingerprint.result?.mutableMethod?.apply {
|
// Find the class name of classes which construct a settings entry
|
||||||
val instructions = implementation!!.instructions
|
val settingsButtonClass = SettingsEntryFingerprint.result?.classDef?.type?.toClassName()
|
||||||
|
?: return SettingsEntryFingerprint.toErrorResult()
|
||||||
|
val settingsButtonInfoClass = SettingsEntryInfoFingerprint.result?.classDef?.type?.toClassName()
|
||||||
|
?: return SettingsEntryInfoFingerprint.toErrorResult()
|
||||||
|
|
||||||
// Find the indices that need to be patched.
|
// Create a settings entry for 'revanced settings' and add it to settings fragment
|
||||||
val copyrightPolicyLabelId = AboutPageFingerprint.result?.let {
|
AddSettingsEntryFingerprint.result?.apply {
|
||||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
scanResult.patternScanResult?.startIndex?.let {
|
||||||
it.mutableMethod.getInstruction<WideLiteralInstruction>(startIndex).wideLiteral
|
val settingsEntries = mutableMethod.getInstruction(it + 3)
|
||||||
} ?: return AboutPageFingerprint.toErrorResult()
|
val addEntry = mutableMethod.getInstruction(it + 5)
|
||||||
|
// Add the settings entry created to the settings fragment
|
||||||
val copyrightIndex = instructions.indexOfFirst {
|
mutableMethod.addInstructions(
|
||||||
(it as? ReferenceInstruction)?.reference.toString() == "copyright_policy"
|
it + 6,
|
||||||
} - 6
|
listOf(
|
||||||
|
settingsEntries,
|
||||||
|
addEntry
|
||||||
// fixme: instead use Method.indexOfFirstConstantInstructionValue()
|
)
|
||||||
val copyrightPolicyIndex = instructions.indexOfFirst {
|
|
||||||
(it as? WideLiteralInstruction)?.wideLiteral == copyrightPolicyLabelId
|
|
||||||
} + 2
|
|
||||||
|
|
||||||
// Replace an existing settings entry with ReVanced settings entry.
|
|
||||||
arrayOf(
|
|
||||||
copyrightIndex,
|
|
||||||
copyrightPolicyIndex
|
|
||||||
).forEach { index ->
|
|
||||||
val instruction = getInstruction(index)
|
|
||||||
if (instruction.opcode != Opcode.MOVE_RESULT_OBJECT)
|
|
||||||
return PatchResultError("Hardcoded offset changed.")
|
|
||||||
|
|
||||||
val settingsEntryStringRegister = (instruction as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
// Replace the settings entry string with a custom one.
|
|
||||||
replaceInstruction(
|
|
||||||
index,
|
|
||||||
"""
|
|
||||||
const-string v$settingsEntryStringRegister, "ReVanced Settings"
|
|
||||||
"""
|
|
||||||
)
|
)
|
||||||
|
// These instructions call a method that create a settings entry use reflection base on the class name of classes that construct settings entry
|
||||||
// Replace the OnClickListener class with a custom one.
|
mutableMethod.addInstructions(
|
||||||
val onClickListener = getInstruction<ReferenceInstruction>(index + 4).reference.toString()
|
it + 6,
|
||||||
|
|
||||||
context.findClass(onClickListener)?.mutableClass?.methods?.first {
|
|
||||||
it.name == "onClick"
|
|
||||||
}?.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
"""
|
||||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->startSettingsActivity()V
|
const-string v1, "$settingsButtonClass"
|
||||||
return-void
|
const-string v2, "$settingsButtonInfoClass"
|
||||||
|
invoke-static {v1, v2}, $CREATE_SETTINGS_ENTRY_METHOD_DESCRIPTOR
|
||||||
|
move-result-object v1
|
||||||
"""
|
"""
|
||||||
) ?: return PatchResultError("Could not find the onClick method.")
|
)
|
||||||
}
|
}
|
||||||
|
} ?: return AddSettingsEntryFingerprint.toErrorResult()
|
||||||
} ?: return SettingsOnViewCreatedFingerprint.toErrorResult()
|
|
||||||
|
|
||||||
// Initialize the settings menu once the replaced setting entry is clicked.
|
// Initialize the settings menu once the replaced setting entry is clicked.
|
||||||
AdPersonalizationActivityOnCreateFingerprint.result?.mutableMethod?.apply {
|
AdPersonalizationActivityOnCreateFingerprint.result?.mutableMethod?.apply {
|
||||||
|
@ -101,18 +75,25 @@ class SettingsPatch : BytecodePatch(
|
||||||
|
|
||||||
val thisRegister = getInstruction<FiveRegisterInstruction>(initializeSettingsIndex - 1).registerC
|
val thisRegister = getInstruction<FiveRegisterInstruction>(initializeSettingsIndex - 1).registerC
|
||||||
|
|
||||||
addInstructions(
|
addInstructionsWithLabels(
|
||||||
initializeSettingsIndex,
|
initializeSettingsIndex,
|
||||||
"""
|
"""
|
||||||
invoke-static {v$thisRegister}, $INITIALIZE_SETTINGS_METHOD_DESCRIPTOR
|
invoke-static {v$thisRegister}, $INITIALIZE_SETTINGS_METHOD_DESCRIPTOR
|
||||||
|
move-result v0
|
||||||
|
if-eqz v0, :notrevanced
|
||||||
return-void
|
return-void
|
||||||
"""
|
""",
|
||||||
|
ExternalLabel("notrevanced", getInstruction(initializeSettingsIndex))
|
||||||
)
|
)
|
||||||
} ?: return AdPersonalizationActivityOnCreateFingerprint.toErrorResult()
|
} ?: return AdPersonalizationActivityOnCreateFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.toClassName(): String {
|
||||||
|
return substring(1, this.length - 1).replace("/", ".")
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/tiktok/settingsmenu/SettingsMenu;"
|
"Lapp/revanced/tiktok/settingsmenu/SettingsMenu;"
|
||||||
|
@ -120,6 +101,11 @@ class SettingsPatch : BytecodePatch(
|
||||||
private const val INITIALIZE_SETTINGS_METHOD_DESCRIPTOR =
|
private const val INITIALIZE_SETTINGS_METHOD_DESCRIPTOR =
|
||||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->initializeSettings(" +
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->initializeSettings(" +
|
||||||
"Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" +
|
"Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" +
|
||||||
")V"
|
")Z"
|
||||||
|
private const val CREATE_SETTINGS_ENTRY_METHOD_DESCRIPTOR =
|
||||||
|
"$INTEGRATIONS_CLASS_DESCRIPTOR->createSettingsEntry(" +
|
||||||
|
"Ljava/lang/String;" +
|
||||||
|
"Ljava/lang/String;" +
|
||||||
|
")Ljava/lang/Object;"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,6 @@ package app.revanced.patches.trakt.annotations
|
||||||
import app.revanced.patcher.annotation.Compatibility
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
import app.revanced.patcher.annotation.Package
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
@Compatibility([Package("tv.trakt.trakt")])
|
@Compatibility([Package("tv.trakt.trakt", arrayOf("1.1.1"))])
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
internal annotation class UnlockProCompatibility
|
internal annotation class UnlockProCompatibility
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patches.youtube.misc.fix.playback.patch.SpoofSignatureVerificationResourcePatch
|
||||||
|
import app.revanced.util.patch.LiteralValueFingerprint
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
object ScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint(
|
||||||
|
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||||
|
returnType = "V",
|
||||||
|
parameters = listOf("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I", "I"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.CONST,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.CHECK_CAST,
|
||||||
|
Opcode.IPUT_OBJECT, // preview imageview
|
||||||
|
),
|
||||||
|
// This resource is used in ~ 40 different locations, but this method has a distinct list of parameters to match to.
|
||||||
|
literal = SpoofSignatureVerificationResourcePatch.scrubbedPreviewThumbnailResourceId
|
||||||
|
)
|
|
@ -0,0 +1,23 @@
|
||||||
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves using the class found in [StoryboardThumbnailParentFingerprint].
|
||||||
|
*/
|
||||||
|
object StoryboardThumbnailFingerprint : MethodFingerprint(
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
returnType = "Z",
|
||||||
|
parameters = listOf(),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_GTZ,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.RETURN,
|
||||||
|
Opcode.RETURN, // Last instruction of method.
|
||||||
|
),
|
||||||
|
)
|
|
@ -0,0 +1,17 @@
|
||||||
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here lies code that creates the seekbar thumbnails.
|
||||||
|
*
|
||||||
|
* An additional change here might force the thumbnails to be created,
|
||||||
|
* or possibly a change somewhere else (maybe involving YouTube 18.23.35 class `hte`)
|
||||||
|
*/
|
||||||
|
object StoryboardThumbnailParentFingerprint : MethodFingerprint(
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
returnType = "Landroid/graphics/Bitmap;",
|
||||||
|
strings = listOf("Storyboard regionDecoder.decodeRegion exception - "),
|
||||||
|
)
|
|
@ -1,6 +1,5 @@
|
||||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
|
|
@ -7,47 +7,35 @@ import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.data.toMethodWalker
|
import app.revanced.patcher.data.toMethodWalker
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
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.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.shared.settings.preference.impl.StringResource
|
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
|
||||||
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
|
||||||
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.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
|
||||||
@Name("Spoof signature verification")
|
@Name("Spoof signature verification")
|
||||||
@Description("Spoofs a patched client to prevent playback issues.")
|
@Description("Spoofs a patched client to prevent playback issues.")
|
||||||
@DependsOn([
|
@DependsOn([
|
||||||
|
SpoofSignatureVerificationResourcePatch::class,
|
||||||
IntegrationsPatch::class,
|
IntegrationsPatch::class,
|
||||||
SettingsPatch::class,
|
PlayerTypeHookPatch::class
|
||||||
PlayerTypeHookPatch::class,
|
|
||||||
])
|
])
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class SpoofSignatureVerificationPatch : BytecodePatch(
|
class SpoofSignatureVerificationPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
ProtobufParameterBuilderFingerprint,
|
ProtobufParameterBuilderFingerprint,
|
||||||
|
StoryboardThumbnailParentFingerprint,
|
||||||
|
ScrubbedPreviewLayoutFingerprint,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
|
||||||
SwitchPreference(
|
|
||||||
"revanced_spoof_signature_verification",
|
|
||||||
StringResource("revanced_spoof_signature_verification_title", "Spoof app signature"),
|
|
||||||
StringResource("revanced_spoof_signature_verification_summary_on",
|
|
||||||
"App signature spoofed\\n\\n"
|
|
||||||
+ "Side effects include:\\n"
|
|
||||||
+ "• Ambient mode may not work\\n"
|
|
||||||
+ "• Seekbar thumbnails are hidden\\n"
|
|
||||||
+ "• Downloading videos may not work"),
|
|
||||||
StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed"),
|
|
||||||
StringResource("revanced_spoof_signature_verification_user_dialog_message",
|
|
||||||
"Turning off this setting may cause playback issues.")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// hook parameter
|
// hook parameter
|
||||||
ProtobufParameterBuilderFingerprint.result?.let {
|
ProtobufParameterBuilderFingerprint.result?.let {
|
||||||
|
@ -68,6 +56,53 @@ class SpoofSignatureVerificationPatch : BytecodePatch(
|
||||||
}
|
}
|
||||||
} ?: return ProtobufParameterBuilderFingerprint.toErrorResult()
|
} ?: return ProtobufParameterBuilderFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
|
||||||
|
// When signature spoofing is enabled, the seekbar when tapped does not show
|
||||||
|
// the video time, chapter names, or the video thumbnail.
|
||||||
|
// Changing the value returned of this method forces all of these to show up,
|
||||||
|
// except the thumbnails are blank, which is handled with the patch below.
|
||||||
|
StoryboardThumbnailParentFingerprint.result ?: return StoryboardThumbnailParentFingerprint.toErrorResult()
|
||||||
|
StoryboardThumbnailFingerprint.resolve(context, StoryboardThumbnailParentFingerprint.result!!.classDef)
|
||||||
|
StoryboardThumbnailFingerprint.result?.apply {
|
||||||
|
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||||
|
// Replace existing instruction to preserve control flow label.
|
||||||
|
// The replaced return instruction always returns false
|
||||||
|
// (it is the 'no thumbnails found' control path),
|
||||||
|
// so there is no need to pass the existing return value to integrations.
|
||||||
|
mutableMethod.replaceInstruction(
|
||||||
|
endIndex,
|
||||||
|
"""
|
||||||
|
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarThumbnailOverrideValue()Z
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
// Since this is end of the method must replace one line then add the rest.
|
||||||
|
mutableMethod.addInstructions(
|
||||||
|
endIndex + 1,
|
||||||
|
"""
|
||||||
|
move-result v0
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
} ?: return StoryboardThumbnailFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
|
||||||
|
// Seekbar thumbnail now show up but are always a blank image.
|
||||||
|
// Additional changes are needed to force the client to generate the thumbnails (assuming it's possible),
|
||||||
|
// but for now hide the empty thumbnail.
|
||||||
|
ScrubbedPreviewLayoutFingerprint.result?.apply {
|
||||||
|
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||||
|
mutableMethod.apply {
|
||||||
|
val imageViewFieldName = getInstruction<ReferenceInstruction>(endIndex).reference
|
||||||
|
addInstructions(
|
||||||
|
implementation!!.instructions.lastIndex,
|
||||||
|
"""
|
||||||
|
iget-object v0, p0, $imageViewFieldName # copy imageview field to a register
|
||||||
|
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->seekbarImageViewCreated(Landroid/widget/ImageView;)V
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return ScrubbedPreviewLayoutFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package app.revanced.patches.youtube.misc.fix.playback.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.misc.fix.playback.fingerprints.*
|
||||||
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
|
|
||||||
|
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class])
|
||||||
|
class SpoofSignatureVerificationResourcePatch : ResourcePatch {
|
||||||
|
|
||||||
|
override fun execute(context: ResourceContext): PatchResult {
|
||||||
|
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||||
|
SwitchPreference(
|
||||||
|
"revanced_spoof_signature_verification",
|
||||||
|
StringResource("revanced_spoof_signature_verification_title", "Spoof app signature"),
|
||||||
|
StringResource("revanced_spoof_signature_verification_summary_on",
|
||||||
|
"App signature spoofed\\n\\n"
|
||||||
|
+ "Side effects include:\\n"
|
||||||
|
+ "• Ambient mode may not work\\n"
|
||||||
|
+ "• Seekbar thumbnails are hidden\\n"
|
||||||
|
+ "• Downloading videos may not work"),
|
||||||
|
StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed"),
|
||||||
|
StringResource("revanced_spoof_signature_verification_user_dialog_message",
|
||||||
|
"Turning off this setting may cause playback issues.")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
scrubbedPreviewThumbnailResourceId = ResourceMappingPatch.resourceMappings.single {
|
||||||
|
it.type == "id" && it.name == "thumbnail"
|
||||||
|
}.id
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var scrubbedPreviewThumbnailResourceId: Long = -1
|
||||||
|
}
|
||||||
|
}
|
|
@ -176,7 +176,7 @@ class LithoFilterPatch : BytecodePatch(
|
||||||
"""
|
"""
|
||||||
new-instance v1, $classDescriptor
|
new-instance v1, $classDescriptor
|
||||||
invoke-direct {v1}, $classDescriptor-><init>()V
|
invoke-direct {v1}, $classDescriptor-><init>()V
|
||||||
const/4 v2, ${filterCount++}
|
const/16 v2, ${filterCount++}
|
||||||
aput-object v1, v0, v2
|
aput-object v1, v0, v2
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -187,7 +187,7 @@ class LithoFilterPatch : BytecodePatch(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() = LithoFilterFingerprint.result!!
|
override fun close() = LithoFilterFingerprint.result!!
|
||||||
.mutableMethod.replaceInstruction(0, "const/4 v0, $filterCount")
|
.mutableMethod.replaceInstruction(0, "const/16 v0, $filterCount")
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val MethodFingerprint.patternScanResult
|
private val MethodFingerprint.patternScanResult
|
||||||
|
@ -208,4 +208,4 @@ class LithoFilterPatch : BytecodePatch(
|
||||||
|
|
||||||
private var filterCount = 0
|
private var filterCount = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package app.revanced.patches.youtube.video.information.fingerprints
|
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
object VideoTimeFingerprint : MethodFingerprint(
|
|
||||||
strings = listOf("MedialibPlayerTimeInfo{currentPositionMillis=")
|
|
||||||
)
|
|
|
@ -10,7 +10,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
@ -44,7 +43,6 @@ class VideoInformationPatch : BytecodePatch(
|
||||||
PlayerInitFingerprint,
|
PlayerInitFingerprint,
|
||||||
CreateVideoPlayerSeekbarFingerprint,
|
CreateVideoPlayerSeekbarFingerprint,
|
||||||
PlayerControllerSetTimeReferenceFingerprint,
|
PlayerControllerSetTimeReferenceFingerprint,
|
||||||
VideoTimeFingerprint,
|
|
||||||
OnPlaybackSpeedItemClickFingerprint,
|
OnPlaybackSpeedItemClickFingerprint,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -118,18 +116,10 @@ class VideoInformationPatch : BytecodePatch(
|
||||||
.getMethod() as MutableMethod
|
.getMethod() as MutableMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the high precision video time method
|
|
||||||
*/
|
|
||||||
highPrecisionTimeMethod =
|
|
||||||
(object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also {
|
|
||||||
it.resolve(context, VideoTimeFingerprint.result!!.classDef)
|
|
||||||
}.result!!.mutableMethod
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hook the methods which set the time
|
* Hook the methods which set the time
|
||||||
*/
|
*/
|
||||||
highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTimeHighPrecision")
|
videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,9 +154,6 @@ class VideoInformationPatch : BytecodePatch(
|
||||||
private lateinit var timeMethod: MutableMethod
|
private lateinit var timeMethod: MutableMethod
|
||||||
private var timeInitInsertIndex = 2
|
private var timeInitInsertIndex = 2
|
||||||
|
|
||||||
private lateinit var highPrecisionTimeMethod: MutableMethod
|
|
||||||
private var highPrecisionInsertIndex = 0
|
|
||||||
|
|
||||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||||
|
|
||||||
|
@ -202,20 +189,6 @@ class VideoInformationPatch : BytecodePatch(
|
||||||
"$targetMethodClass->$targetMethodName(J)V"
|
"$targetMethodClass->$targetMethodName(J)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook the high precision video time.
|
|
||||||
* The hooks is called extremely often (10 to 15 times a seconds), so use with caution.
|
|
||||||
* Note: the hook is usually called _off_ the main thread
|
|
||||||
*
|
|
||||||
* @param targetMethodClass The descriptor for the static method to invoke when the player controller is created.
|
|
||||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
|
||||||
*/
|
|
||||||
internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) =
|
|
||||||
highPrecisionTimeMethod.insertTimeHook(
|
|
||||||
highPrecisionInsertIndex++,
|
|
||||||
"$targetMethodClass->$targetMethodName(J)V"
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) =
|
private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) =
|
||||||
(instructions[instructions.indexOfFirst { it.opcode == opcode } + offset] as ReferenceInstruction)
|
(instructions[instructions.indexOfFirst { it.opcode == opcode } + offset] as ReferenceInstruction)
|
||||||
.reference.toString()
|
.reference.toString()
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
package app.revanced.patches.youtube.video.speed
|
package app.revanced.patches.youtube.video.speed
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
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.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patches.youtube.video.speed.custom.patch.CustomVideoSpeedPatch
|
import app.revanced.patches.youtube.video.speed.custom.patch.CustomPlaybackSpeedPatch
|
||||||
import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackSpeedPatch
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("Video speed")
|
@Name("Playback speed")
|
||||||
@Description("Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.")
|
@Description("Adds custom playback speeds and ability to remember the playback speed you chose in the video playback speed flyout.")
|
||||||
@DependsOn([CustomVideoSpeedPatch::class, RememberPlaybackSpeedPatch::class])
|
@DependsOn([CustomPlaybackSpeedPatch::class, RememberPlaybackSpeedPatch::class])
|
||||||
@VideoSpeedCompatibility
|
@PlaybackSpeedCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class VideoSpeed : BytecodePatch() {
|
class PlaybackSpeed : BytecodePatch() {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
return PatchResultSuccess() // All patches this patch depends on succeed.
|
return PatchResultSuccess() // All patches this patch depends on succeed.
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,4 +5,4 @@ import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
@Compatibility([Package("com.google.android.youtube", arrayOf("18.20.39", "18.23.35"))])
|
@Compatibility([Package("com.google.android.youtube", arrayOf("18.20.39", "18.23.35"))])
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
internal annotation class VideoSpeedCompatibility
|
internal annotation class PlaybackSpeedCompatibility
|
|
@ -2,7 +2,7 @@ package app.revanced.patches.youtube.video.speed.custom.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
object GetOldVideoSpeedsFingerprint : MethodFingerprint(
|
object GetOldPlaybackSpeedsFingerprint : MethodFingerprint(
|
||||||
parameters = listOf("[L", "I"),
|
parameters = listOf("[L", "I"),
|
||||||
strings = listOf("menu_item_playback_speed")
|
strings = listOf("menu_item_playback_speed")
|
||||||
)
|
)
|
|
@ -2,6 +2,6 @@ package app.revanced.patches.youtube.video.speed.custom.fingerprints
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
object ShowOldVideoSpeedMenuFingerprint : MethodFingerprint(
|
object ShowOldPlaybackSpeedMenuFingerprint : MethodFingerprint(
|
||||||
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
|
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
|
||||||
)
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package app.revanced.patches.youtube.video.speed.custom.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
|
object ShowOldPlaybackSpeedMenuIntegrationsFingerprint : MethodFingerprint(
|
||||||
|
customFingerprint = { method, _ -> method.name == "showOldPlaybackSpeedMenu" }
|
||||||
|
)
|
|
@ -1,7 +0,0 @@
|
||||||
package app.revanced.patches.youtube.video.speed.custom.fingerprints
|
|
||||||
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|
||||||
|
|
||||||
object ShowOldVideoSpeedMenuIntegrationsFingerprint : MethodFingerprint(
|
|
||||||
customFingerprint = { method, _ -> method.name == "showOldVideoSpeedMenu" }
|
|
||||||
)
|
|
|
@ -31,16 +31,16 @@ import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
import org.jf.dexlib2.immutable.ImmutableField
|
import org.jf.dexlib2.immutable.ImmutableField
|
||||||
|
|
||||||
@Name("Custom video speed")
|
@Name("Custom playback speed")
|
||||||
@Description("Adds custom video speed options.")
|
@Description("Adds custom playback speed options.")
|
||||||
@DependsOn([IntegrationsPatch::class, LithoFilterPatch::class, SettingsPatch::class, BottomSheetHookPatch::class])
|
@DependsOn([IntegrationsPatch::class, LithoFilterPatch::class, SettingsPatch::class, BottomSheetHookPatch::class])
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class CustomVideoSpeedPatch : BytecodePatch(
|
class CustomPlaybackSpeedPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
SpeedArrayGeneratorFingerprint,
|
SpeedArrayGeneratorFingerprint,
|
||||||
SpeedLimiterFingerprint,
|
SpeedLimiterFingerprint,
|
||||||
GetOldVideoSpeedsFingerprint,
|
GetOldPlaybackSpeedsFingerprint,
|
||||||
ShowOldVideoSpeedMenuIntegrationsFingerprint
|
ShowOldPlaybackSpeedMenuIntegrationsFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -81,12 +81,12 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
|
|
||||||
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
|
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
val videoSpeedsArrayType = "$INTEGRATIONS_CLASS_DESCRIPTOR->customVideoSpeeds:[F"
|
val playbackSpeedsArrayType = "$INTEGRATIONS_CLASS_DESCRIPTOR->customPlaybackSpeeds:[F"
|
||||||
|
|
||||||
arrayGenMethod.addInstructions(
|
arrayGenMethod.addInstructions(
|
||||||
arrayLengthConstIndex + 1,
|
arrayLengthConstIndex + 1,
|
||||||
"""
|
"""
|
||||||
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
|
sget-object v$arrayLengthConstDestination, $playbackSpeedsArrayType
|
||||||
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
|
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
@ -102,7 +102,7 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
|
|
||||||
arrayGenMethod.replaceInstruction(
|
arrayGenMethod.replaceInstruction(
|
||||||
originalArrayFetchIndex,
|
originalArrayFetchIndex,
|
||||||
"sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType"
|
"sget-object v$originalArrayFetchDestination, $playbackSpeedsArrayType"
|
||||||
)
|
)
|
||||||
|
|
||||||
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!
|
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!
|
||||||
|
@ -121,24 +121,24 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
// edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x
|
// edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x
|
||||||
limiterMethod.replaceInstruction(
|
limiterMethod.replaceInstruction(
|
||||||
limiterMinConstIndex,
|
limiterMinConstIndex,
|
||||||
"sget v$limiterMinConstDestination, $INTEGRATIONS_CLASS_DESCRIPTOR->minVideoSpeed:F"
|
"sget v$limiterMinConstDestination, $INTEGRATIONS_CLASS_DESCRIPTOR->minPlaybackSpeed:F"
|
||||||
)
|
)
|
||||||
limiterMethod.replaceInstruction(
|
limiterMethod.replaceInstruction(
|
||||||
limiterMaxConstIndex,
|
limiterMaxConstIndex,
|
||||||
"sget v$limiterMaxConstDestination, $INTEGRATIONS_CLASS_DESCRIPTOR->maxVideoSpeed:F"
|
"sget v$limiterMaxConstDestination, $INTEGRATIONS_CLASS_DESCRIPTOR->maxPlaybackSpeed:F"
|
||||||
)
|
)
|
||||||
|
|
||||||
// region Force old video quality menu.
|
// region Force old video quality menu.
|
||||||
// This is necessary, because there is no known way of adding custom video speeds to the new menu.
|
// This is necessary, because there is no known way of adding custom playback speeds to the new menu.
|
||||||
|
|
||||||
BottomSheetHookPatch.addHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
BottomSheetHookPatch.addHook(INTEGRATIONS_CLASS_DESCRIPTOR)
|
||||||
|
|
||||||
// Required to check if the video speed menu is currently shown.
|
// Required to check if the playback speed menu is currently shown.
|
||||||
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
||||||
|
|
||||||
GetOldVideoSpeedsFingerprint.result?.let { result ->
|
GetOldPlaybackSpeedsFingerprint.result?.let { result ->
|
||||||
// Add a static INSTANCE field to the class.
|
// Add a static INSTANCE field to the class.
|
||||||
// This is later used to call "showOldVideoSpeedMenu" on the instance.
|
// This is later used to call "showOldPlaybackSpeedMenu" on the instance.
|
||||||
val instanceField = ImmutableField(
|
val instanceField = ImmutableField(
|
||||||
result.classDef.type,
|
result.classDef.type,
|
||||||
"INSTANCE",
|
"INSTANCE",
|
||||||
|
@ -154,15 +154,15 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
// In order to prevent a conflict with another patch, add the instruction at index 1.
|
// In order to prevent a conflict with another patch, add the instruction at index 1.
|
||||||
result.mutableMethod.addInstruction(1, "sput-object p0, $instanceField")
|
result.mutableMethod.addInstruction(1, "sput-object p0, $instanceField")
|
||||||
|
|
||||||
// Get the "showOldVideoSpeedMenu" method.
|
// Get the "showOldPlaybackSpeedMenu" method.
|
||||||
// This is later called on the field INSTANCE.
|
// This is later called on the field INSTANCE.
|
||||||
val showOldVideoSpeedMenuMethod = ShowOldVideoSpeedMenuFingerprint.also {
|
val showOldPlaybackSpeedMenuMethod = ShowOldPlaybackSpeedMenuFingerprint.also {
|
||||||
if (!it.resolve(context, result.classDef))
|
if (!it.resolve(context, result.classDef))
|
||||||
throw ShowOldVideoSpeedMenuFingerprint.toErrorResult()
|
throw ShowOldPlaybackSpeedMenuFingerprint.toErrorResult()
|
||||||
}.result!!.method.toString()
|
}.result!!.method.toString()
|
||||||
|
|
||||||
// Insert the call to the "showOldVideoSpeedMenu" method on the field INSTANCE.
|
// Insert the call to the "showOldPlaybackSpeedMenu" method on the field INSTANCE.
|
||||||
ShowOldVideoSpeedMenuIntegrationsFingerprint.result?.mutableMethod?.apply {
|
ShowOldPlaybackSpeedMenuIntegrationsFingerprint.result?.mutableMethod?.apply {
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
implementation!!.instructions.lastIndex,
|
implementation!!.instructions.lastIndex,
|
||||||
"""
|
"""
|
||||||
|
@ -170,11 +170,11 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
if-nez v0, :not_null
|
if-nez v0, :not_null
|
||||||
return-void
|
return-void
|
||||||
:not_null
|
:not_null
|
||||||
invoke-virtual { v0 }, $showOldVideoSpeedMenuMethod
|
invoke-virtual { v0 }, $showOldPlaybackSpeedMenuMethod
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
} ?: return ShowOldVideoSpeedMenuIntegrationsFingerprint.toErrorResult()
|
} ?: return ShowOldPlaybackSpeedMenuIntegrationsFingerprint.toErrorResult()
|
||||||
} ?: return GetOldVideoSpeedsFingerprint.toErrorResult()
|
} ?: return GetOldPlaybackSpeedsFingerprint.toErrorResult()
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
@ -183,10 +183,10 @@ class CustomVideoSpeedPatch : BytecodePatch(
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private const val FILTER_CLASS_DESCRIPTOR =
|
private const val FILTER_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/patches/components/VideoSpeedMenuFilterPatch;"
|
"Lapp/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch;"
|
||||||
|
|
||||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;"
|
"Lapp/revanced/integrations/patches/playback/speed/CustomPlaybackSpeedPatch;"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,13 +19,13 @@ import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
|
||||||
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.video.speed.custom.patch.CustomVideoSpeedPatch
|
import app.revanced.patches.youtube.video.speed.custom.patch.CustomPlaybackSpeedPatch
|
||||||
import app.revanced.patches.youtube.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
|
import app.revanced.patches.youtube.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
|
||||||
@Name("Remember playback speed")
|
@Name("Remember playback speed")
|
||||||
@Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.")
|
@Description("Adds the ability to remember the playback speed you chose in the playback speed flyout.")
|
||||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomVideoSpeedPatch::class])
|
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomPlaybackSpeedPatch::class])
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RememberPlaybackSpeedPatch : BytecodePatch(
|
class RememberPlaybackSpeedPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
|
|
Loading…
Reference in a new issue