mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-04 16:44:29 +02:00
refactor(YouTube/Video information): include playback speed
This commit is contained in:
parent
d6bdef650f
commit
7ba43b6f4c
@ -8,7 +8,7 @@ import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.utils.fingerprints.QualityMenuViewInflateFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.VideoQualitySetterFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.QualitySetterFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.FLYOUT_PANEL_CLASS_DESCRIPTOR
|
||||
@ -38,7 +38,7 @@ object OldQualityLayoutPatch : BaseBytecodePatch(
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
QualityMenuViewInflateFingerprint,
|
||||
VideoQualitySetterFingerprint
|
||||
QualitySetterFingerprint
|
||||
)
|
||||
) {
|
||||
private const val FILTER_CLASS_DESCRIPTOR =
|
||||
@ -49,7 +49,7 @@ object OldQualityLayoutPatch : BaseBytecodePatch(
|
||||
/**
|
||||
* Non-litho view, used in old clients and Shorts.
|
||||
*/
|
||||
val videoQualityClass = VideoQualitySetterFingerprint.resultOrThrow().mutableMethod.definingClass
|
||||
val videoQualityClass = QualitySetterFingerprint.resultOrThrow().mutableMethod.definingClass
|
||||
|
||||
QualityMenuViewInflateFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
|
@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
|
||||
@Suppress("unused")
|
||||
@ -20,7 +20,7 @@ object AutoCaptionsPatch : BaseBytecodePatch(
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
VideoIdPatch.injectCall("$GENERAL_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$GENERAL_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
|
||||
/**
|
||||
* Add settings
|
||||
|
@ -6,9 +6,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patches.youtube.overlaybutton.alwaysrepeat.fingerprints.AutoNavInformerFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
|
||||
import app.revanced.util.getTargetIndexReversed
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
object AlwaysRepeatPatch : BytecodePatch(
|
||||
setOf(AutoNavInformerFingerprint)
|
||||
@ -18,8 +21,8 @@ object AlwaysRepeatPatch : BytecodePatch(
|
||||
AutoNavInformerFingerprint.resultOrThrow().let {
|
||||
val walkerMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
||||
walkerMethod.apply {
|
||||
val index = implementation!!.instructions.size - 2
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
val index = getTargetIndexReversed(Opcode.IGET_BOOLEAN)
|
||||
val register = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||
|
||||
addInstructions(
|
||||
index + 1, """
|
||||
|
@ -9,11 +9,9 @@ import app.revanced.patches.youtube.overlaybutton.fullscreen.FullscreenButtonPat
|
||||
import app.revanced.patches.youtube.utils.fix.fullscreen.FullscreenButtonViewStubPatch
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.OVERLAY_BUTTONS_PATH
|
||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.utils.playercontrols.PlayerControlsPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.copyResources
|
||||
import app.revanced.util.copyXmlNode
|
||||
@ -31,11 +29,9 @@ object OverlayButtonsPatch : BaseResourcePatch(
|
||||
DownloadButtonHookPatch::class,
|
||||
FullscreenButtonPatch::class,
|
||||
FullscreenButtonViewStubPatch::class,
|
||||
OverrideSpeedHookPatch::class,
|
||||
PlayerControlsPatch::class,
|
||||
SettingsPatch::class,
|
||||
SharedResourceIdPatch::class,
|
||||
VideoIdPatch::class
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE
|
||||
) {
|
||||
|
@ -7,9 +7,9 @@ import app.revanced.patches.youtube.utils.fingerprints.TotalTimeFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.SEEKBAR_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch
|
||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
@ -22,9 +22,9 @@ object AppendTimeStampInformationPatch : BaseBytecodePatch(
|
||||
description = "Adds an option to add the current video quality or playback speed in brackets next to the current time.",
|
||||
dependencies = setOf(
|
||||
OverrideQualityHookPatch::class,
|
||||
OverrideSpeedHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
SharedResourceIdPatch::class,
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(TotalTimeFingerprint)
|
||||
|
@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object NewVideoQualityChangedFingerprint : MethodFingerprint(
|
||||
internal object QualityChangedFromRecyclerViewFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object VideoQualitySetterFingerprint : MethodFingerprint(
|
||||
internal object QualitySetterFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
@ -16,10 +16,10 @@ import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardT
|
||||
import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardThumbnailParentFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH
|
||||
import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@ -30,9 +30,9 @@ object SpoofPlayerParameterPatch : BaseBytecodePatch(
|
||||
description = "Adds options to spoof player parameters to prevent playback issues.",
|
||||
dependencies = setOf(
|
||||
PlayerTypeHookPatch::class,
|
||||
PlayerResponsePatch::class,
|
||||
VideoIdPatch::class,
|
||||
SettingsPatch::class
|
||||
PlayerResponseMethodHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
@ -52,7 +52,7 @@ object SpoofPlayerParameterPatch : BaseBytecodePatch(
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
// Hook the player parameters.
|
||||
PlayerResponsePatch += PlayerResponsePatch.Hook.PlayerParameter(
|
||||
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.PlayerParameter(
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;"
|
||||
)
|
||||
|
||||
|
@ -1,150 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.overridespeed
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import app.revanced.patches.youtube.utils.overridespeed.fingerprints.PlaybackSpeedChangedFingerprint
|
||||
import app.revanced.patches.youtube.utils.overridespeed.fingerprints.PlaybackSpeedParentFingerprint
|
||||
import app.revanced.patches.youtube.utils.overridespeed.fingerprints.PlaybackSpeedPatchFingerprint
|
||||
import app.revanced.patches.youtube.utils.overridespeed.fingerprints.SpeedClassFingerprint
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
|
||||
object OverrideSpeedHookPatch : BytecodePatch(
|
||||
setOf(
|
||||
PlaybackSpeedPatchFingerprint,
|
||||
PlaybackSpeedParentFingerprint,
|
||||
SpeedClassFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/PlaybackSpeedPatch;"
|
||||
|
||||
private const val INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR =
|
||||
"$INTEGRATIONS_PATH/utils/VideoUtils;"
|
||||
|
||||
lateinit var playbackSpeedChangedResult: MethodFingerprintResult
|
||||
|
||||
private lateinit var objectClass: String
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
PlaybackSpeedParentFingerprint.resultOrThrow().let { parentResult ->
|
||||
val parentClassDef = parentResult.classDef
|
||||
|
||||
PlaybackSpeedChangedFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentClassDef
|
||||
)
|
||||
}.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
playbackSpeedChangedResult = it
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
val reference1 = getInstruction<ReferenceInstruction>(startIndex).reference
|
||||
val reference2 = getInstruction<ReferenceInstruction>(endIndex - 1).reference
|
||||
val reference3 = getInstruction<ReferenceInstruction>(endIndex).reference
|
||||
val fieldReference = reference2 as FieldReference
|
||||
|
||||
val parentMutableClass = parentResult.mutableClass
|
||||
|
||||
parentMutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
parentMutableClass.type,
|
||||
"overrideSpeed",
|
||||
listOf(ImmutableMethodParameter("F", annotations, null)),
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.PUBLIC,
|
||||
annotations,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
4, """
|
||||
const/4 v0, 0x0
|
||||
cmpg-float v0, v3, v0
|
||||
if-lez v0, :cond_0
|
||||
iget-object v0, v2, $reference1
|
||||
check-cast v0, ${fieldReference.definingClass}
|
||||
iget-object v1, v0, $reference2
|
||||
invoke-virtual {v1, v3}, $reference3
|
||||
:cond_0
|
||||
return-void
|
||||
""".toInstructions(), null, null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
val walkerMethod = getWalkerMethod(context, endIndex)
|
||||
|
||||
walkerMethod.apply {
|
||||
addInstruction(
|
||||
this.implementation!!.instructions.size - 1,
|
||||
"sput p1, $INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR->currentSpeed:F"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SpeedClassFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val index = it.scanResult.patternScanResult!!.endIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
objectClass = this.returnType
|
||||
replaceInstruction(
|
||||
index,
|
||||
"sput-object v$register, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->speedClass:$objectClass"
|
||||
)
|
||||
addInstruction(
|
||||
index + 1,
|
||||
"return-object v$register"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackSpeedPatchFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
it.mutableClass.staticFields.add(
|
||||
ImmutableField(
|
||||
definingClass,
|
||||
"speedClass",
|
||||
objectClass,
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
addInstructions(
|
||||
0, """
|
||||
sget-object v0, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->speedClass:$objectClass
|
||||
invoke-virtual {v0, p0}, $objectClass->overrideSpeed(F)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.overridespeed.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PlaybackSpeedChangedFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
),
|
||||
customFingerprint = { methodDef, _ -> methodDef.name == "onItemClick" }
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.overridespeed.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PlaybackSpeedParentFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("L", "L", "[L", "I"),
|
||||
opcodes = listOf(
|
||||
Opcode.ARRAY_LENGTH,
|
||||
Opcode.IF_GE,
|
||||
Opcode.AGET_OBJECT,
|
||||
Opcode.NEW_INSTANCE
|
||||
)
|
||||
)
|
@ -1,102 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.playerresponse
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.utils.playerresponse.fingerprints.PlayerParameterBuilderFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import java.io.Closeable
|
||||
|
||||
object PlayerResponsePatch : BytecodePatch(
|
||||
setOf(PlayerParameterBuilderFingerprint)
|
||||
), Closeable, MutableSet<PlayerResponsePatch.Hook> by mutableSetOf() {
|
||||
private var VIDEO_ID_PARAMETER = 1
|
||||
private var PLAYER_PARAMETER = 3
|
||||
private var IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER = 11
|
||||
private var freeRegister = 0
|
||||
private var shouldApplyNewMethod = false
|
||||
|
||||
private lateinit var playerResponseMethod: MutableMethod
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod
|
||||
|
||||
playerResponseMethod.apply {
|
||||
freeRegister = implementation!!.registerCount - parameters.size - 2
|
||||
shouldApplyNewMethod = freeRegister > 2
|
||||
if (shouldApplyNewMethod) {
|
||||
IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER = freeRegister
|
||||
PLAYER_PARAMETER = freeRegister - 1
|
||||
VIDEO_ID_PARAMETER = freeRegister - 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
fun hookVideoId(hook: Hook) {
|
||||
playerResponseMethod.apply {
|
||||
val instruction =
|
||||
if (shouldApplyNewMethod)
|
||||
"invoke-static {v$VIDEO_ID_PARAMETER, v$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook"
|
||||
else
|
||||
"invoke-static {p$VIDEO_ID_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook"
|
||||
addInstruction(
|
||||
0,
|
||||
instruction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun hookPlayerParameter(hook: Hook) {
|
||||
playerResponseMethod.apply {
|
||||
val instruction =
|
||||
if (shouldApplyNewMethod)
|
||||
"""
|
||||
invoke-static {v$VIDEO_ID_PARAMETER, v$PLAYER_PARAMETER, v$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook
|
||||
move-result-object p3
|
||||
"""
|
||||
else
|
||||
"""
|
||||
invoke-static {p$VIDEO_ID_PARAMETER, p$PLAYER_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook
|
||||
move-result-object p$PLAYER_PARAMETER
|
||||
"""
|
||||
addInstructions(
|
||||
0,
|
||||
instruction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the order in order to preserve insertion order of the hooks.
|
||||
val beforeVideoIdHooks = filterIsInstance<Hook.PlayerBeforeVideoId>().asReversed()
|
||||
val videoIdHooks = filterIsInstance<Hook.VideoId>().asReversed()
|
||||
val afterVideoIdHooks = filterIsInstance<Hook.PlayerParameter>().asReversed()
|
||||
|
||||
// Add the hooks in this specific order as they insert instructions at the beginning of the method.
|
||||
afterVideoIdHooks.forEach(::hookPlayerParameter)
|
||||
videoIdHooks.forEach(::hookVideoId)
|
||||
beforeVideoIdHooks.forEach(::hookPlayerParameter)
|
||||
|
||||
if (shouldApplyNewMethod) {
|
||||
playerResponseMethod.addInstructions(
|
||||
0, """
|
||||
move-object v$VIDEO_ID_PARAMETER, p1
|
||||
move-object v$PLAYER_PARAMETER, p3
|
||||
move/from16 v$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER, p11
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class Hook(private val methodDescriptor: String) {
|
||||
internal class VideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||
|
||||
internal class PlayerParameter(methodDescriptor: String) : Hook(methodDescriptor)
|
||||
internal class PlayerBeforeVideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||
|
||||
override fun toString() = methodDescriptor
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
|
||||
import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.DislikeFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.LikeFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.RemoveLikeFingerprint
|
||||
@ -17,7 +16,7 @@ import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerpri
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.ReturnYouTubeDislikeRollingNumberPatch
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.shorts.ReturnYouTubeDislikeShortsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceType
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
@ -30,7 +29,6 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch(
|
||||
description = "Shows the dislike count of videos using the Return YouTube Dislike API.",
|
||||
dependencies = setOf(
|
||||
LithoFilterPatch::class,
|
||||
PlayerResponsePatch::class,
|
||||
ReturnYouTubeDislikeRollingNumberPatch::class,
|
||||
ReturnYouTubeDislikeShortsPatch::class,
|
||||
SettingsPatch::class,
|
||||
@ -91,14 +89,22 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
VideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
|
||||
VideoIdPatch.injectPlayerResponseVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->preloadVideoId(Ljava/lang/String;Z)V")
|
||||
// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
|
||||
VideoIdPatch.hookVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
|
||||
|
||||
// Hook the player response video id, to start loading RYD sooner in the background.
|
||||
VideoIdPatch.hookPlayerResponseVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->preloadVideoId(Ljava/lang/String;Z)V")
|
||||
|
||||
// endregion
|
||||
|
||||
// Player response video id is needed to search for the video ids in Shorts litho components.
|
||||
if (SettingsPatch.upward1834) {
|
||||
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
||||
VideoIdPatch.injectPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V")
|
||||
VideoIdPatch.hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V")
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Add ReVanced Extended Settings
|
||||
*/
|
||||
|
@ -12,14 +12,13 @@ import app.revanced.patches.youtube.utils.fingerprints.SeekbarOnDrawFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.TotalTimeFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH
|
||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.utils.playercontrols.PlayerControlsPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.InsetOverlayViewLayout
|
||||
import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint
|
||||
import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.SegmentPlaybackControllerFingerprint
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.withoutshorts.VideoIdWithoutShortsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceTypeReversed
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
||||
@ -34,11 +33,10 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
OverrideSpeedHookPatch::class,
|
||||
PlayerControlsPatch::class,
|
||||
SharedResourceIdPatch::class,
|
||||
VideoIdPatch::class,
|
||||
VideoIdWithoutShortsPatch::class
|
||||
VideoInformationPatch::class
|
||||
]
|
||||
)
|
||||
object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
@ -60,13 +58,13 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
VideoIdPatch.apply {
|
||||
VideoInformationPatch.apply {
|
||||
// Hook the video time method
|
||||
videoTimeHook(
|
||||
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
||||
"setVideoTime"
|
||||
)
|
||||
// Initialize SponsorBlock
|
||||
// Initialize the player controller
|
||||
onCreateHook(
|
||||
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
||||
"initialize"
|
||||
@ -163,7 +161,7 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
// Inject VideoIdPatch
|
||||
VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
// Set current video id
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.videocpn
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(dependencies = [VideoIdPatch::class])
|
||||
object VideoCpnPatch : BytecodePatch(
|
||||
setOf(OrganicPlaybackContextModelFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
insertMethod = OrganicPlaybackContextModelFingerprint.resultOrThrow().mutableMethod
|
||||
|
||||
}
|
||||
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
|
||||
internal fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
2,
|
||||
"invoke-static {p1}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,247 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.general
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.general.fingerprint.PlayerControllerSetTimeReferenceFingerprint
|
||||
import app.revanced.patches.youtube.utils.videoid.general.fingerprint.VideoIdFingerprint
|
||||
import app.revanced.patches.youtube.utils.videoid.general.fingerprint.VideoIdParentFingerprint
|
||||
import app.revanced.patches.youtube.utils.videoid.general.fingerprint.VideoLengthFingerprint
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Patch(
|
||||
dependencies = [
|
||||
PlayerTypeHookPatch::class,
|
||||
PlayerResponsePatch::class
|
||||
]
|
||||
)
|
||||
object VideoIdPatch : BytecodePatch(
|
||||
setOf(
|
||||
OrganicPlaybackContextModelFingerprint,
|
||||
PlayerControllerSetTimeReferenceFingerprint,
|
||||
VideoEndFingerprint,
|
||||
VideoIdParentFingerprint,
|
||||
VideoLengthFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
VideoEndFingerprint.resultOrThrow().let {
|
||||
playerInitMethod =
|
||||
it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) }
|
||||
|
||||
// hook the player controller for use through integrations
|
||||
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val seekHelperMethod = ImmutableMethod(
|
||||
definingClass,
|
||||
"seekTo",
|
||||
listOf(ImmutableMethodParameter("J", annotations, "time")),
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
annotations, null,
|
||||
MutableMethodImplementation(4)
|
||||
).toMutable()
|
||||
|
||||
val seekSourceEnumType = parameterTypes[1].toString()
|
||||
|
||||
seekHelperMethod.addInstructions(
|
||||
0, """
|
||||
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
||||
invoke-virtual {p0, p1, p2, v0}, ${definingClass}->${name}(J$seekSourceEnumType)Z
|
||||
move-result p1
|
||||
return p1
|
||||
"""
|
||||
)
|
||||
it.mutableClass.methods.add(seekHelperMethod)
|
||||
|
||||
val videoEndMethod = getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex + 1)
|
||||
|
||||
videoEndMethod.apply {
|
||||
addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->videoEnded()Z
|
||||
move-result v0
|
||||
if-eqz v0, :end
|
||||
return-void
|
||||
""", ExternalLabel("end", getInstruction(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video time
|
||||
*/
|
||||
PlayerControllerSetTimeReferenceFingerprint.resultOrThrow().let {
|
||||
timeMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook the methods which set the time
|
||||
*/
|
||||
videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
|
||||
|
||||
/**
|
||||
* Set current video is livestream
|
||||
*/
|
||||
OrganicPlaybackContextModelFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
addInstruction(
|
||||
2,
|
||||
"sput-boolean p2, $INTEGRATIONS_CLASS_DESCRIPTOR->isLiveStream:Z"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video length
|
||||
*/
|
||||
VideoLengthFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val primaryRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA
|
||||
val secondaryRegister = primaryRegister + 1
|
||||
|
||||
addInstruction(
|
||||
startIndex + 2,
|
||||
"invoke-static {v$primaryRegister, v$secondaryRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
VideoIdParentFingerprint.resultOrThrow().let { parentResult ->
|
||||
VideoIdFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentResult.classDef
|
||||
)
|
||||
}.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
insertMethod = this
|
||||
insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
videoIdRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
}
|
||||
offset++ // offset so setVideoId is called before any injected call
|
||||
}
|
||||
}
|
||||
|
||||
injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||
injectPlayerResponseVideoId("$INTEGRATIONS_CLASS_DESCRIPTOR->setPlayerResponseVideoId(Ljava/lang/String;Z)V")
|
||||
// Call before any other video id hooks,
|
||||
// so they can use VideoInformation and check if the video id is for a Short.
|
||||
PlayerResponsePatch += PlayerResponsePatch.Hook.PlayerBeforeVideoId(
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;"
|
||||
)
|
||||
}
|
||||
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR = "$VIDEO_PATH/VideoInformation;"
|
||||
|
||||
private var offset = 0
|
||||
private var playerInitInsertIndex = 4
|
||||
private var timeInitInsertIndex = 2
|
||||
|
||||
private var insertIndex: Int = 0
|
||||
private var videoIdRegister: Int = 0
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
private lateinit var playerInitMethod: MutableMethod
|
||||
private lateinit var timeMethod: MutableMethod
|
||||
|
||||
/**
|
||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
internal fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
insertIndex + offset, // move-result-object offset
|
||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks the video id of every video when loaded.
|
||||
* Supports all videos and functions in all situations.
|
||||
*
|
||||
* First parameter is the video id.
|
||||
* Second parameter is if the video is a Short AND it is being opened or is currently playing.
|
||||
*
|
||||
* Hook is always called off the main thread.
|
||||
*
|
||||
* This hook is called as soon as the player response is parsed,
|
||||
* and called before many other hooks are updated such as [PlayerTypeHookPatch].
|
||||
*
|
||||
* Note: The video id returned here may not be the current video that's being played.
|
||||
* It's common for multiple Shorts to load at once in preparation
|
||||
* for the user swiping to the next Short.
|
||||
*
|
||||
* Be aware, this can be called multiple times for the same video id.
|
||||
*
|
||||
* @param methodDescriptor which method to call. Params must be `Ljava/lang/String;Z`
|
||||
*/
|
||||
internal fun injectPlayerResponseVideoId(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
PlayerResponsePatch += PlayerResponsePatch.Hook.VideoId(
|
||||
methodDescriptor
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||
|
||||
private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) =
|
||||
insert(insertIndex, "p1, p2", descriptor)
|
||||
|
||||
/**
|
||||
* Hook the player controller. Called when a video is opened or the current video is changed.
|
||||
*
|
||||
* Note: This hook is called very early and is called before the video id, video time, video length,
|
||||
* and many other data fields are set.
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
|
||||
playerInitMethod.insert(
|
||||
playerInitInsertIndex++,
|
||||
"v0",
|
||||
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||
)
|
||||
|
||||
/**
|
||||
* Hook the video time.
|
||||
* The hook is usually called once per second.
|
||||
*
|
||||
* @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 videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||
timeMethod.insertTimeHook(
|
||||
timeInitInsertIndex++,
|
||||
"$targetMethodClass->$targetMethodName(J)V"
|
||||
)
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.withoutshorts
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import app.revanced.patches.youtube.utils.videoid.withoutshorts.fingerprint.VideoIdWithoutShortsFingerprint
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
object VideoIdWithoutShortsPatch : BytecodePatch(
|
||||
setOf(VideoIdWithoutShortsFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
VideoIdWithoutShortsFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
insertMethod = this
|
||||
insertIndex = getTargetIndex(Opcode.INVOKE_INTERFACE)
|
||||
insertRegister = getInstruction<OneRegisterInstruction>(insertIndex + 1).registerA
|
||||
}
|
||||
}
|
||||
|
||||
injectCall("$VIDEO_PATH/VideoInformation;->setVideoId(Ljava/lang/String;)V")
|
||||
|
||||
}
|
||||
|
||||
private var offset = 2
|
||||
|
||||
private var insertIndex: Int = 0
|
||||
private var insertRegister: Int = 0
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
|
||||
|
||||
/**
|
||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
internal fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
insertIndex + offset, // move-result-object offset
|
||||
"invoke-static {v$insertRegister}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package app.revanced.patches.youtube.video.customspeed
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patches.youtube.flyoutpanel.oldspeedlayout.OldSpeedLayoutPatch
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.patch.BaseResourcePatch
|
||||
|
||||
@Suppress("unused")
|
||||
@ -14,8 +14,8 @@ object CustomPlaybackSpeedPatch : BaseResourcePatch(
|
||||
dependencies = setOf(
|
||||
CustomPlaybackSpeedBytecodePatch::class,
|
||||
OldSpeedLayoutPatch::class,
|
||||
OverrideSpeedHookPatch::class,
|
||||
SettingsPatch::class
|
||||
SettingsPatch::class,
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE
|
||||
) {
|
||||
|
@ -0,0 +1,313 @@
|
||||
package app.revanced.patches.youtube.video.information
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.replaceInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.OnPlaybackSpeedItemClickFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.PlaybackSpeedClassFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.PlayerControllerSetTimeReferenceFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.VideoInformationPatchFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.VideoLengthFingerprint
|
||||
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.getTargetIndexReversed
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
@Patch(
|
||||
description = "Hooks YouTube to get information about the current playing video.",
|
||||
dependencies = [
|
||||
PlayerResponseMethodHookPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
VideoIdPatch::class
|
||||
]
|
||||
)
|
||||
object VideoInformationPatch : BytecodePatch(
|
||||
setOf(
|
||||
OnPlaybackSpeedItemClickFingerprint,
|
||||
OrganicPlaybackContextModelFingerprint,
|
||||
PlaybackSpeedClassFingerprint,
|
||||
PlayerControllerSetTimeReferenceFingerprint,
|
||||
VideoEndFingerprint,
|
||||
VideoInformationPatchFingerprint,
|
||||
VideoLengthFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/VideoInformation;"
|
||||
|
||||
private lateinit var playerConstructorMethod: MutableMethod
|
||||
private var playerConstructorInsertIndex = 4
|
||||
|
||||
private lateinit var videoTimeConstructorMethod: MutableMethod
|
||||
private var videoTimeConstructorInsertIndex = 2
|
||||
|
||||
private lateinit var videoCpnConstructorMethod: MutableMethod
|
||||
private var videoCpnConstructorInsertIndex = 2
|
||||
|
||||
// Used by other patches.
|
||||
internal lateinit var speedSelectionInsertMethod: MutableMethod
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
VideoEndFingerprint.resultOrThrow().let {
|
||||
playerConstructorMethod =
|
||||
it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) }
|
||||
|
||||
// hook the player controller for use through integrations
|
||||
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val seekSourceEnumType = parameterTypes[1].toString()
|
||||
|
||||
it.mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
"seekTo",
|
||||
listOf(ImmutableMethodParameter("J", annotations, "time")),
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
annotations,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
4, """
|
||||
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
||||
invoke-virtual {p0, p1, p2, v0}, ${definingClass}->${name}(J$seekSourceEnumType)Z
|
||||
move-result p1
|
||||
return p1
|
||||
""".toInstructions(),
|
||||
null,
|
||||
null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
val videoEndMethod = getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex + 1)
|
||||
|
||||
videoEndMethod.apply {
|
||||
addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->videoEnded()Z
|
||||
move-result v0
|
||||
if-eqz v0, :end
|
||||
return-void
|
||||
""", ExternalLabel("end", getInstruction(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video time method
|
||||
*/
|
||||
PlayerControllerSetTimeReferenceFingerprint.resultOrThrow().let {
|
||||
videoTimeConstructorMethod =
|
||||
it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video time
|
||||
*/
|
||||
videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
|
||||
|
||||
/**
|
||||
* Set current video length
|
||||
*/
|
||||
VideoLengthFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val primaryRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA
|
||||
val secondaryRegister = primaryRegister + 1
|
||||
|
||||
addInstruction(
|
||||
startIndex + 2,
|
||||
"invoke-static {v$primaryRegister, v$secondaryRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video is livestream
|
||||
*/
|
||||
videoCpnConstructorMethod = OrganicPlaybackContextModelFingerprint.resultOrThrow().mutableMethod
|
||||
cpnHook("$INTEGRATIONS_CLASS_DESCRIPTOR->setLiveStreamState(Ljava/lang/String;Z)V")
|
||||
|
||||
/**
|
||||
* Set current video id
|
||||
*/
|
||||
val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V"
|
||||
VideoIdPatch.hookVideoId(videoIdMethodDescriptor)
|
||||
VideoIdPatch.hookBackgroundPlayVideoId(videoIdMethodDescriptor)
|
||||
VideoIdPatch.hookPlayerResponseVideoId(
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->setPlayerResponseVideoId(Ljava/lang/String;Z)V")
|
||||
// Call before any other video id hooks,
|
||||
// so they can use VideoInformation and check if the video id is for a Short.
|
||||
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.PlayerParameterBeforeVideoId(
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerResponseParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;")
|
||||
|
||||
/**
|
||||
* Hook the user playback speed selection
|
||||
*/
|
||||
OnPlaybackSpeedItemClickFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
speedSelectionInsertMethod = this
|
||||
val speedSelectionValueInstructionIndex = getTargetIndex(Opcode.IGET)
|
||||
|
||||
val setPlaybackSpeedContainerClassFieldIndex = getTargetIndexReversed(speedSelectionValueInstructionIndex, Opcode.IGET_OBJECT)
|
||||
val setPlaybackSpeedContainerClassFieldReference =
|
||||
getInstruction<ReferenceInstruction>(setPlaybackSpeedContainerClassFieldIndex).reference.toString()
|
||||
|
||||
val setPlaybackSpeedClassFieldReference =
|
||||
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 1).reference.toString()
|
||||
val setPlaybackSpeedMethodReference =
|
||||
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 2).reference.toString()
|
||||
|
||||
it.mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
"overridePlaybackSpeed",
|
||||
listOf(ImmutableMethodParameter("F", annotations, null)),
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.PUBLIC,
|
||||
annotations,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
4, """
|
||||
const/4 v0, 0x0
|
||||
cmpg-float v0, v3, v0
|
||||
if-lez v0, :ignore
|
||||
|
||||
# Get the container class field.
|
||||
iget-object v0, v2, $setPlaybackSpeedContainerClassFieldReference
|
||||
|
||||
# Get the field from its class.
|
||||
iget-object v1, v0, $setPlaybackSpeedClassFieldReference
|
||||
|
||||
# Invoke setPlaybackSpeed on that class.
|
||||
invoke-virtual {v1, v3}, $setPlaybackSpeedMethodReference
|
||||
|
||||
:ignore
|
||||
return-void
|
||||
""".toInstructions(), null, null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
val walkerMethod = getWalkerMethod(context, speedSelectionValueInstructionIndex + 2)
|
||||
|
||||
walkerMethod.apply {
|
||||
addInstruction(
|
||||
this.implementation!!.instructions.size - 1,
|
||||
"invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackSpeedClassFingerprint.resultOrThrow().let { result ->
|
||||
result.mutableMethod.apply {
|
||||
val index = result.scanResult.patternScanResult!!.endIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
val playbackSpeedClass = this.returnType
|
||||
replaceInstruction(
|
||||
index,
|
||||
"sput-object v$register, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackSpeedClass:$playbackSpeedClass"
|
||||
)
|
||||
addInstruction(
|
||||
index + 1,
|
||||
"return-object v$register"
|
||||
)
|
||||
|
||||
VideoInformationPatchFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
it.mutableClass.staticFields.add(
|
||||
ImmutableField(
|
||||
definingClass,
|
||||
"playbackSpeedClass",
|
||||
playbackSpeedClass,
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
annotations,
|
||||
null
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
addInstructions(
|
||||
0, """
|
||||
sget-object v0, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackSpeedClass:$playbackSpeedClass
|
||||
invoke-virtual {v0, p0}, $playbackSpeedClass->overridePlaybackSpeed(F)V
|
||||
return-void
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||
|
||||
private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) =
|
||||
insert(insertIndex, "p1, p2", descriptor)
|
||||
|
||||
/**
|
||||
* Hook the player controller. Called when a video is opened or the current video is changed.
|
||||
*
|
||||
* Note: This hook is called very early and is called before the video id, video time, video length,
|
||||
* and many other data fields are set.
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
|
||||
playerConstructorMethod.insert(
|
||||
playerConstructorInsertIndex++,
|
||||
"v0",
|
||||
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||
)
|
||||
|
||||
/**
|
||||
* Hook the video time.
|
||||
* The hook is usually called once per second.
|
||||
*
|
||||
* @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 videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||
videoTimeConstructorMethod.insertTimeHook(
|
||||
videoTimeConstructorInsertIndex++,
|
||||
"$targetMethodClass->$targetMethodName(J)V"
|
||||
)
|
||||
|
||||
internal fun cpnHook(descriptor: String) =
|
||||
videoCpnConstructorMethod.insert(
|
||||
videoCpnConstructorInsertIndex++,
|
||||
"p1, p2",
|
||||
descriptor
|
||||
)
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroid/widget/AdapterView;", "Landroid/view/View;", "I", "J"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.name == "onItemClick" && methodDef.implementation?.instructions?.find {
|
||||
it.opcode == Opcode.IGET_OBJECT &&
|
||||
it.getReference<FieldReference>()!!.type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"
|
||||
} != null
|
||||
}
|
||||
)
|
@ -1,11 +1,11 @@
|
||||
package app.revanced.patches.youtube.utils.overridespeed.fingerprints
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object SpeedClassFingerprint : MethodFingerprint(
|
||||
internal object PlaybackSpeedClassFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("L"),
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.general.fingerprint
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
@ -1,16 +1,16 @@
|
||||
package app.revanced.patches.youtube.utils.overridespeed.fingerprints
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object PlaybackSpeedPatchFingerprint : MethodFingerprint(
|
||||
internal object VideoInformationPatchFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("F"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass == "$VIDEO_PATH/PlaybackSpeedPatch;"
|
||||
&& methodDef.name == "overrideSpeed"
|
||||
methodDef.definingClass == "$VIDEO_PATH/VideoInformation;"
|
||||
&& methodDef.name == "overridePlaybackSpeed"
|
||||
}
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.general.fingerprint
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.util.fingerprint.LiteralValueFingerprint
|
@ -0,0 +1,106 @@
|
||||
package app.revanced.patches.youtube.video.playerresponse
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import java.io.Closeable
|
||||
|
||||
object PlayerResponseMethodHookPatch :
|
||||
BytecodePatch(setOf(PlayerParameterBuilderFingerprint)),
|
||||
Closeable,
|
||||
MutableSet<PlayerResponseMethodHookPatch.Hook> by mutableSetOf() {
|
||||
|
||||
// Parameter numbers of the patched method.
|
||||
private var PARAMETER_VIDEO_ID = 1
|
||||
private var PARAMETER_PLAYER_PARAMETER = 3
|
||||
private var PARAMETER_PLAYLIST_ID = 4
|
||||
private var PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11
|
||||
|
||||
private var freeRegister = 0
|
||||
private var shouldApplyNewMethod = false
|
||||
|
||||
private lateinit var playerResponseMethod: MutableMethod
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod
|
||||
|
||||
playerResponseMethod.apply {
|
||||
freeRegister = implementation!!.registerCount - parameters.size - 2
|
||||
shouldApplyNewMethod = freeRegister > 2
|
||||
if (shouldApplyNewMethod) {
|
||||
PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = freeRegister
|
||||
PARAMETER_PLAYLIST_ID = freeRegister - 1
|
||||
PARAMETER_PLAYER_PARAMETER = freeRegister - 2
|
||||
PARAMETER_VIDEO_ID = freeRegister - 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
fun hookVideoId(hook: Hook) {
|
||||
val instruction =
|
||||
if (shouldApplyNewMethod)
|
||||
"invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
|
||||
else
|
||||
"invoke-static {p$PARAMETER_VIDEO_ID, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook"
|
||||
|
||||
playerResponseMethod.addInstruction(
|
||||
0, instruction
|
||||
)
|
||||
}
|
||||
|
||||
fun hookPlayerParameter(hook: Hook) {
|
||||
val instruction =
|
||||
if (shouldApplyNewMethod)
|
||||
"""
|
||||
invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_PLAYER_PARAMETER, v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
|
||||
move-result-object p3
|
||||
"""
|
||||
else
|
||||
"""
|
||||
invoke-static {p$PARAMETER_VIDEO_ID, p$PARAMETER_PLAYER_PARAMETER, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
|
||||
move-result-object p$PARAMETER_PLAYER_PARAMETER
|
||||
"""
|
||||
|
||||
playerResponseMethod.addInstructions(
|
||||
0,
|
||||
instruction
|
||||
)
|
||||
}
|
||||
|
||||
// Reverse the order in order to preserve insertion order of the hooks.
|
||||
val beforeVideoIdHooks = filterIsInstance<Hook.PlayerParameterBeforeVideoId>().asReversed()
|
||||
val videoIdHooks = filterIsInstance<Hook.VideoId>().asReversed()
|
||||
val afterVideoIdHooks = filterIsInstance<Hook.PlayerParameter>().asReversed()
|
||||
|
||||
// Add the hooks in this specific order as they insert instructions at the beginning of the method.
|
||||
afterVideoIdHooks.forEach(::hookPlayerParameter)
|
||||
videoIdHooks.forEach(::hookVideoId)
|
||||
beforeVideoIdHooks.forEach(::hookPlayerParameter)
|
||||
|
||||
if (shouldApplyNewMethod) {
|
||||
playerResponseMethod.addInstructions(
|
||||
0, """
|
||||
move-object v$PARAMETER_VIDEO_ID, p1
|
||||
move-object v$PARAMETER_PLAYER_PARAMETER, p3
|
||||
move-object v$PARAMETER_PLAYLIST_ID, p4
|
||||
move/from16 v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING, p11
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class Hook(private val methodDescriptor: String) {
|
||||
internal class VideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||
|
||||
internal class PlayerParameter(methodDescriptor: String) : Hook(methodDescriptor)
|
||||
internal class PlayerParameterBeforeVideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||
|
||||
override fun toString() = methodDescriptor
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.utils.playerresponse.fingerprints
|
||||
package app.revanced.patches.youtube.video.playerresponse.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
@ -11,7 +11,7 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
|
||||
"Ljava/lang/String;", // VideoId.
|
||||
"[B",
|
||||
"Ljava/lang/String;", // Player parameters proto buffer.
|
||||
"Ljava/lang/String;",
|
||||
"Ljava/lang/String;", // PlaylistId.
|
||||
"I",
|
||||
"I",
|
||||
"Ljava/util/Set;",
|
@ -4,18 +4,17 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patches.youtube.utils.fingerprints.NewVideoQualityChangedFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.VideoQualitySetterFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.QualityChangedFromRecyclerViewFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.QualitySetterFingerprint
|
||||
import app.revanced.patches.youtube.utils.fix.shortsplayback.ShortsPlaybackPatch
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch
|
||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.withoutshorts.VideoIdWithoutShortsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.copyXmlNode
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
@ -27,22 +26,27 @@ object VideoQualityPatch : BaseBytecodePatch(
|
||||
description = "Adds an option to set the default video quality.",
|
||||
dependencies = setOf(
|
||||
OverrideQualityHookPatch::class,
|
||||
OverrideSpeedHookPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
ShortsPlaybackPatch::class,
|
||||
VideoIdPatch::class,
|
||||
VideoIdWithoutShortsPatch::class
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
NewVideoQualityChangedFingerprint,
|
||||
VideoQualitySetterFingerprint
|
||||
QualityChangedFromRecyclerViewFingerprint,
|
||||
QualitySetterFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/VideoQualityPatch;"
|
||||
private const val INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/ReloadVideoPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
NewVideoQualityChangedFingerprint.resultOrThrow().let {
|
||||
// Remember video quality from recyclerview (litho view).
|
||||
QualityChangedFromRecyclerViewFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val index = it.scanResult.patternScanResult!!.startIndex
|
||||
val qualityRegister = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||
@ -55,7 +59,7 @@ object VideoQualityPatch : BaseBytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
VideoQualitySetterFingerprint.resultOrThrow().let {
|
||||
QualitySetterFingerprint.resultOrThrow().let {
|
||||
val onItemClickMethod =
|
||||
it.mutableClass.methods.find { method -> method.name == "onItemClick" }
|
||||
|
||||
@ -69,10 +73,8 @@ object VideoQualityPatch : BaseBytecodePatch(
|
||||
} ?: throw PatchException("Failed to find onItemClick method")
|
||||
}
|
||||
|
||||
VideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
|
||||
VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||
|
||||
/**
|
||||
* Copy arrays
|
||||
@ -94,9 +96,4 @@ object VideoQualityPatch : BaseBytecodePatch(
|
||||
SettingsPatch.updatePatchStatus("Default video quality")
|
||||
|
||||
}
|
||||
|
||||
private const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/VideoQualityPatch;"
|
||||
private const val INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/ReloadVideoPatch;"
|
||||
}
|
@ -4,34 +4,35 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patches.youtube.utils.fingerprints.NewVideoQualityChangedFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.QualityChangedFromRecyclerViewFingerprint
|
||||
import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.videocpn.VideoCpnPatch
|
||||
import app.revanced.patches.youtube.video.speed.fingerprints.NewPlaybackSpeedChangedFingerprint
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch.speedSelectionInsertMethod
|
||||
import app.revanced.patches.youtube.video.speed.fingerprints.PlaybackSpeedChangedFromRecyclerViewFingerprint
|
||||
import app.revanced.patches.youtube.video.speed.fingerprints.PlaybackSpeedInitializeFingerprint
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import app.revanced.util.updatePatchStatus
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
object PlaybackSpeedPatch : BaseBytecodePatch(
|
||||
name = "Default playback speed",
|
||||
description = "Adds an option to set the default playback speed.",
|
||||
dependencies = setOf(
|
||||
OverrideSpeedHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
VideoCpnPatch::class
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
NewVideoQualityChangedFingerprint,
|
||||
QualityChangedFromRecyclerViewFingerprint,
|
||||
VideoEndFingerprint
|
||||
)
|
||||
) {
|
||||
@ -40,24 +41,27 @@ object PlaybackSpeedPatch : BaseBytecodePatch(
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
NewVideoQualityChangedFingerprint.resultOrThrow().let { parentResult ->
|
||||
NewPlaybackSpeedChangedFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentResult.classDef
|
||||
)
|
||||
}.resultOrThrow().let { result ->
|
||||
arrayOf(result, OverrideSpeedHookPatch.playbackSpeedChangedResult).forEach {
|
||||
it.mutableMethod.apply {
|
||||
val index = it.scanResult.patternScanResult!!.endIndex
|
||||
val register = getInstruction<FiveRegisterInstruction>(index).registerD
|
||||
PlaybackSpeedChangedFromRecyclerViewFingerprint.resolve(
|
||||
context,
|
||||
QualityChangedFromRecyclerViewFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
|
||||
addInstruction(
|
||||
index,
|
||||
"invoke-static {v$register}, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->userChangedSpeed(F)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
val newMethod = PlaybackSpeedChangedFromRecyclerViewFingerprint.resultOrThrow().mutableMethod
|
||||
|
||||
arrayOf(
|
||||
newMethod,
|
||||
speedSelectionInsertMethod
|
||||
).forEach {
|
||||
it.apply {
|
||||
val speedSelectionValueInstructionIndex = getTargetIndex(Opcode.IGET)
|
||||
val speedSelectionValueRegister =
|
||||
getInstruction<TwoRegisterInstruction>(speedSelectionValueInstructionIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
speedSelectionValueInstructionIndex + 1,
|
||||
"invoke-static {v$speedSelectionValueRegister}, " +
|
||||
"$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->userSelectedPlaybackSpeed(F)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +86,7 @@ object PlaybackSpeedPatch : BaseBytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
VideoCpnPatch.injectCall("$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
VideoInformationPatch.cpnHook("$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Z)V")
|
||||
|
||||
/**
|
||||
* Add settings
|
||||
|
@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object NewPlaybackSpeedChangedFingerprint : MethodFingerprint(
|
||||
internal object PlaybackSpeedChangedFromRecyclerViewFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
@ -0,0 +1,136 @@
|
||||
package app.revanced.patches.youtube.video.videoid
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdFingerprint
|
||||
import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdParentFingerprint
|
||||
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
||||
import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdFingerprintBackgroundPlay
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
description = "Hooks to detect when the video id changes",
|
||||
dependencies = [PlayerResponseMethodHookPatch::class],
|
||||
)
|
||||
object VideoIdPatch : BytecodePatch(
|
||||
setOf(
|
||||
VideoIdParentFingerprint,
|
||||
VideoIdFingerprintBackgroundPlay
|
||||
)
|
||||
) {
|
||||
private var videoIdRegister = 0
|
||||
private var videoIdInsertIndex = 0
|
||||
private lateinit var videoIdMethod: MutableMethod
|
||||
|
||||
private var backgroundPlaybackVideoIdRegister = 0
|
||||
private var backgroundPlaybackInsertIndex = 0
|
||||
private lateinit var backgroundPlaybackMethod: MutableMethod
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
/**
|
||||
* Supplies the method and register index of the video id register.
|
||||
*
|
||||
* @param consumer Consumer that receives the method, insert index and video id register index.
|
||||
*/
|
||||
fun MethodFingerprint.setFields(consumer: (MutableMethod, Int, Int) -> Unit) = resultOrThrow().let { result ->
|
||||
val videoIdRegisterIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
result.mutableMethod.let {
|
||||
val videoIdRegister = it.getInstruction<OneRegisterInstruction>(videoIdRegisterIndex).registerA
|
||||
val insertIndex = videoIdRegisterIndex + 1
|
||||
consumer(it, insertIndex, videoIdRegister)
|
||||
}
|
||||
}
|
||||
|
||||
VideoIdFingerprint.resolve(context, VideoIdParentFingerprint.resultOrThrow().classDef)
|
||||
|
||||
VideoIdFingerprint.setFields { method, index, register ->
|
||||
videoIdMethod = method
|
||||
videoIdInsertIndex = index
|
||||
videoIdRegister = register
|
||||
}
|
||||
|
||||
VideoIdFingerprintBackgroundPlay.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
backgroundPlaybackMethod = this
|
||||
backgroundPlaybackInsertIndex = getTargetIndex(Opcode.INVOKE_INTERFACE) + 2
|
||||
backgroundPlaybackVideoIdRegister = getInstruction<OneRegisterInstruction>(backgroundPlaybackInsertIndex - 1).registerA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks the new video id when the video changes.
|
||||
*
|
||||
* Supports all videos (regular videos and Shorts).
|
||||
*
|
||||
* _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 hookVideoId(
|
||||
methodDescriptor: String
|
||||
) = videoIdMethod.addInstruction(
|
||||
videoIdInsertIndex++,
|
||||
"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_.
|
||||
*
|
||||
* 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 hookBackgroundPlayVideoId(
|
||||
methodDescriptor: String
|
||||
) = backgroundPlaybackMethod.addInstruction(
|
||||
backgroundPlaybackInsertIndex++, // move-result-object offset
|
||||
"invoke-static {v$backgroundPlaybackVideoIdRegister}, $methodDescriptor"
|
||||
)
|
||||
|
||||
/**
|
||||
* Hooks the video id of every video when loaded.
|
||||
* Supports all videos and functions in all situations.
|
||||
*
|
||||
* First parameter is the video id.
|
||||
* Second parameter is if the video is a Short AND it is being opened or is currently playing.
|
||||
*
|
||||
* Hook is always called off the main thread.
|
||||
*
|
||||
* This hook is called as soon as the player response is parsed,
|
||||
* and called before many other hooks are updated such as [PlayerTypeHookPatch].
|
||||
*
|
||||
* Note: The video id returned here may not be the current video that's being played.
|
||||
* It's common for multiple Shorts to load at once in preparation
|
||||
* for the user swiping to the next Short.
|
||||
*
|
||||
* For most use cases, you probably want to use
|
||||
* [hookVideoId] or [hookBackgroundPlayVideoId] instead.
|
||||
*
|
||||
* Be aware, this can be called multiple times for the same video id.
|
||||
*
|
||||
* @param methodDescriptor which method to call. Params must be `Ljava/lang/String;Z`
|
||||
*/
|
||||
fun hookPlayerResponseVideoId(methodDescriptor: String) {
|
||||
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.VideoId(
|
||||
methodDescriptor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.general.fingerprint
|
||||
package app.revanced.patches.youtube.video.videoid.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
@ -1,11 +1,14 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.withoutshorts.fingerprint
|
||||
package app.revanced.patches.youtube.video.videoid.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object VideoIdWithoutShortsFingerprint : MethodFingerprint(
|
||||
/**
|
||||
* Renamed from VideoIdWithoutShortsFingerprint
|
||||
*/
|
||||
internal object VideoIdFingerprintBackgroundPlay : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED,
|
||||
parameters = listOf("L"),
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.utils.videoid.general.fingerprint
|
||||
package app.revanced.patches.youtube.video.videoid.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
Loading…
x
Reference in New Issue
Block a user