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.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.shared.litho.LithoFilterPatch
|
import app.revanced.patches.shared.litho.LithoFilterPatch
|
||||||
import app.revanced.patches.youtube.utils.fingerprints.QualityMenuViewInflateFingerprint
|
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.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
|
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.FLYOUT_PANEL_CLASS_DESCRIPTOR
|
import app.revanced.patches.youtube.utils.integrations.Constants.FLYOUT_PANEL_CLASS_DESCRIPTOR
|
||||||
@ -38,7 +38,7 @@ object OldQualityLayoutPatch : BaseBytecodePatch(
|
|||||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||||
fingerprints = setOf(
|
fingerprints = setOf(
|
||||||
QualityMenuViewInflateFingerprint,
|
QualityMenuViewInflateFingerprint,
|
||||||
VideoQualitySetterFingerprint
|
QualitySetterFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
private const val FILTER_CLASS_DESCRIPTOR =
|
private const val FILTER_CLASS_DESCRIPTOR =
|
||||||
@ -49,7 +49,7 @@ object OldQualityLayoutPatch : BaseBytecodePatch(
|
|||||||
/**
|
/**
|
||||||
* Non-litho view, used in old clients and Shorts.
|
* Non-litho view, used in old clients and Shorts.
|
||||||
*/
|
*/
|
||||||
val videoQualityClass = VideoQualitySetterFingerprint.resultOrThrow().mutableMethod.definingClass
|
val videoQualityClass = QualitySetterFingerprint.resultOrThrow().mutableMethod.definingClass
|
||||||
|
|
||||||
QualityMenuViewInflateFingerprint.resultOrThrow().let {
|
QualityMenuViewInflateFingerprint.resultOrThrow().let {
|
||||||
it.mutableMethod.apply {
|
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.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
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.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
|
import app.revanced.util.patch.BaseBytecodePatch
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@ -20,7 +20,7 @@ object AutoCaptionsPatch : BaseBytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext) {
|
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
|
* Add settings
|
||||||
|
@ -6,9 +6,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patches.youtube.overlaybutton.alwaysrepeat.fingerprints.AutoNavInformerFingerprint
|
import app.revanced.patches.youtube.overlaybutton.alwaysrepeat.fingerprints.AutoNavInformerFingerprint
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
|
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
|
||||||
|
import app.revanced.util.getTargetIndexReversed
|
||||||
import app.revanced.util.getWalkerMethod
|
import app.revanced.util.getWalkerMethod
|
||||||
import app.revanced.util.resultOrThrow
|
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.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
object AlwaysRepeatPatch : BytecodePatch(
|
object AlwaysRepeatPatch : BytecodePatch(
|
||||||
setOf(AutoNavInformerFingerprint)
|
setOf(AutoNavInformerFingerprint)
|
||||||
@ -18,8 +21,8 @@ object AlwaysRepeatPatch : BytecodePatch(
|
|||||||
AutoNavInformerFingerprint.resultOrThrow().let {
|
AutoNavInformerFingerprint.resultOrThrow().let {
|
||||||
val walkerMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
val walkerMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
||||||
walkerMethod.apply {
|
walkerMethod.apply {
|
||||||
val index = implementation!!.instructions.size - 2
|
val index = getTargetIndexReversed(Opcode.IGET_BOOLEAN)
|
||||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
val register = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
index + 1, """
|
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.fix.fullscreen.FullscreenButtonViewStubPatch
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
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.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.playercontrols.PlayerControlsPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
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.ResourceGroup
|
||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
import app.revanced.util.copyXmlNode
|
import app.revanced.util.copyXmlNode
|
||||||
@ -31,11 +29,9 @@ object OverlayButtonsPatch : BaseResourcePatch(
|
|||||||
DownloadButtonHookPatch::class,
|
DownloadButtonHookPatch::class,
|
||||||
FullscreenButtonPatch::class,
|
FullscreenButtonPatch::class,
|
||||||
FullscreenButtonViewStubPatch::class,
|
FullscreenButtonViewStubPatch::class,
|
||||||
OverrideSpeedHookPatch::class,
|
|
||||||
PlayerControlsPatch::class,
|
PlayerControlsPatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
SharedResourceIdPatch::class,
|
VideoInformationPatch::class
|
||||||
VideoIdPatch::class
|
|
||||||
),
|
),
|
||||||
compatiblePackages = COMPATIBLE_PACKAGE
|
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.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.SEEKBAR_CLASS_DESCRIPTOR
|
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.overridequality.OverrideQualityHookPatch
|
||||||
import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch
|
|
||||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
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.getTargetIndexWithMethodReferenceName
|
||||||
import app.revanced.util.patch.BaseBytecodePatch
|
import app.revanced.util.patch.BaseBytecodePatch
|
||||||
import app.revanced.util.resultOrThrow
|
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.",
|
description = "Adds an option to add the current video quality or playback speed in brackets next to the current time.",
|
||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
OverrideQualityHookPatch::class,
|
OverrideQualityHookPatch::class,
|
||||||
OverrideSpeedHookPatch::class,
|
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
SharedResourceIdPatch::class
|
SharedResourceIdPatch::class,
|
||||||
|
VideoInformationPatch::class
|
||||||
),
|
),
|
||||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||||
fingerprints = setOf(TotalTimeFingerprint)
|
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.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object NewVideoQualityChangedFingerprint : MethodFingerprint(
|
internal object QualityChangedFromRecyclerViewFingerprint : MethodFingerprint(
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("L"),
|
parameters = listOf("L"),
|
@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or
|
|||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
internal object VideoQualitySetterFingerprint : MethodFingerprint(
|
internal object QualitySetterFingerprint : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("L"),
|
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.fix.parameter.fingerprints.StoryboardThumbnailParentFingerprint
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
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.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.playertype.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
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.patch.BaseBytecodePatch
|
||||||
import app.revanced.util.resultOrThrow
|
import app.revanced.util.resultOrThrow
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
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.",
|
description = "Adds options to spoof player parameters to prevent playback issues.",
|
||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
PlayerTypeHookPatch::class,
|
PlayerTypeHookPatch::class,
|
||||||
PlayerResponsePatch::class,
|
PlayerResponseMethodHookPatch::class,
|
||||||
VideoIdPatch::class,
|
SettingsPatch::class,
|
||||||
SettingsPatch::class
|
VideoInformationPatch::class,
|
||||||
),
|
),
|
||||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||||
fingerprints = setOf(
|
fingerprints = setOf(
|
||||||
@ -52,7 +52,7 @@ object SpoofPlayerParameterPatch : BaseBytecodePatch(
|
|||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
|
||||||
// Hook the player parameters.
|
// 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;"
|
"$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.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH
|
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.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.DislikeFingerprint
|
||||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.LikeFingerprint
|
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.LikeFingerprint
|
||||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.RemoveLikeFingerprint
|
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.rollingnumber.ReturnYouTubeDislikeRollingNumberPatch
|
||||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.shorts.ReturnYouTubeDislikeShortsPatch
|
import app.revanced.patches.youtube.utils.returnyoutubedislike.shorts.ReturnYouTubeDislikeShortsPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
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.getTargetIndexWithFieldReferenceType
|
||||||
import app.revanced.util.patch.BaseBytecodePatch
|
import app.revanced.util.patch.BaseBytecodePatch
|
||||||
import app.revanced.util.resultOrThrow
|
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.",
|
description = "Shows the dislike count of videos using the Return YouTube Dislike API.",
|
||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
LithoFilterPatch::class,
|
LithoFilterPatch::class,
|
||||||
PlayerResponsePatch::class,
|
|
||||||
ReturnYouTubeDislikeRollingNumberPatch::class,
|
ReturnYouTubeDislikeRollingNumberPatch::class,
|
||||||
ReturnYouTubeDislikeShortsPatch::class,
|
ReturnYouTubeDislikeShortsPatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
@ -91,14 +89,22 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
|
// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
|
||||||
VideoIdPatch.injectPlayerResponseVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->preloadVideoId(Ljava/lang/String;Z)V")
|
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) {
|
if (SettingsPatch.upward1834) {
|
||||||
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
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
|
* 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.TotalTimeFingerprint
|
||||||
import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint
|
import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH
|
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.playercontrols.PlayerControlsPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.InsetOverlayViewLayout
|
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.RectangleFieldInvalidatorFingerprint
|
||||||
import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.SegmentPlaybackControllerFingerprint
|
import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.SegmentPlaybackControllerFingerprint
|
||||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.utils.videoid.withoutshorts.VideoIdWithoutShortsPatch
|
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||||
import app.revanced.util.getTargetIndex
|
import app.revanced.util.getTargetIndex
|
||||||
import app.revanced.util.getTargetIndexWithFieldReferenceTypeReversed
|
import app.revanced.util.getTargetIndexWithFieldReferenceTypeReversed
|
||||||
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
||||||
@ -34,11 +33,10 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
dependencies = [
|
dependencies = [
|
||||||
OverrideSpeedHookPatch::class,
|
|
||||||
PlayerControlsPatch::class,
|
PlayerControlsPatch::class,
|
||||||
SharedResourceIdPatch::class,
|
SharedResourceIdPatch::class,
|
||||||
VideoIdPatch::class,
|
VideoIdPatch::class,
|
||||||
VideoIdWithoutShortsPatch::class
|
VideoInformationPatch::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
object SponsorBlockBytecodePatch : BytecodePatch(
|
object SponsorBlockBytecodePatch : BytecodePatch(
|
||||||
@ -60,13 +58,13 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
|
||||||
VideoIdPatch.apply {
|
VideoInformationPatch.apply {
|
||||||
// Hook the video time method
|
// Hook the video time method
|
||||||
videoTimeHook(
|
videoTimeHook(
|
||||||
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
||||||
"setVideoTime"
|
"setVideoTime"
|
||||||
)
|
)
|
||||||
// Initialize SponsorBlock
|
// Initialize the player controller
|
||||||
onCreateHook(
|
onCreateHook(
|
||||||
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
|
||||||
"initialize"
|
"initialize"
|
||||||
@ -163,7 +161,7 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject VideoIdPatch
|
// Set current video id
|
||||||
VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
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.patcher.data.ResourceContext
|
||||||
import app.revanced.patches.youtube.flyoutpanel.oldspeedlayout.OldSpeedLayoutPatch
|
import app.revanced.patches.youtube.flyoutpanel.oldspeedlayout.OldSpeedLayoutPatch
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
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.utils.settings.SettingsPatch
|
||||||
|
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||||
import app.revanced.util.patch.BaseResourcePatch
|
import app.revanced.util.patch.BaseResourcePatch
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@ -14,8 +14,8 @@ object CustomPlaybackSpeedPatch : BaseResourcePatch(
|
|||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
CustomPlaybackSpeedBytecodePatch::class,
|
CustomPlaybackSpeedBytecodePatch::class,
|
||||||
OldSpeedLayoutPatch::class,
|
OldSpeedLayoutPatch::class,
|
||||||
OverrideSpeedHookPatch::class,
|
SettingsPatch::class,
|
||||||
SettingsPatch::class
|
VideoInformationPatch::class
|
||||||
),
|
),
|
||||||
compatiblePackages = COMPATIBLE_PACKAGE
|
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.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object SpeedClassFingerprint : MethodFingerprint(
|
internal object PlaybackSpeedClassFingerprint : MethodFingerprint(
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
parameters = listOf("L"),
|
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 app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
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.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
internal object PlaybackSpeedPatchFingerprint : MethodFingerprint(
|
internal object VideoInformationPatchFingerprint : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
parameters = listOf("F"),
|
parameters = listOf("F"),
|
||||||
customFingerprint = { methodDef, _ ->
|
customFingerprint = { methodDef, _ ->
|
||||||
methodDef.definingClass == "$VIDEO_PATH/PlaybackSpeedPatch;"
|
methodDef.definingClass == "$VIDEO_PATH/VideoInformation;"
|
||||||
&& methodDef.name == "overrideSpeed"
|
&& 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.patcher.extensions.or
|
||||||
import app.revanced.util.fingerprint.LiteralValueFingerprint
|
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.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
@ -11,7 +11,7 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint(
|
|||||||
"Ljava/lang/String;", // VideoId.
|
"Ljava/lang/String;", // VideoId.
|
||||||
"[B",
|
"[B",
|
||||||
"Ljava/lang/String;", // Player parameters proto buffer.
|
"Ljava/lang/String;", // Player parameters proto buffer.
|
||||||
"Ljava/lang/String;",
|
"Ljava/lang/String;", // PlaylistId.
|
||||||
"I",
|
"I",
|
||||||
"I",
|
"I",
|
||||||
"Ljava/util/Set;",
|
"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.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.PatchException
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patches.youtube.utils.fingerprints.NewVideoQualityChangedFingerprint
|
import app.revanced.patches.youtube.utils.fingerprints.QualityChangedFromRecyclerViewFingerprint
|
||||||
import app.revanced.patches.youtube.utils.fingerprints.VideoQualitySetterFingerprint
|
import app.revanced.patches.youtube.utils.fingerprints.QualitySetterFingerprint
|
||||||
import app.revanced.patches.youtube.utils.fix.shortsplayback.ShortsPlaybackPatch
|
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.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
|
||||||
import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch
|
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.playertype.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
|
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
|
||||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.utils.videoid.withoutshorts.VideoIdWithoutShortsPatch
|
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||||
import app.revanced.util.copyXmlNode
|
import app.revanced.util.copyXmlNode
|
||||||
import app.revanced.util.patch.BaseBytecodePatch
|
import app.revanced.util.patch.BaseBytecodePatch
|
||||||
import app.revanced.util.resultOrThrow
|
import app.revanced.util.resultOrThrow
|
||||||
@ -27,22 +26,27 @@ object VideoQualityPatch : BaseBytecodePatch(
|
|||||||
description = "Adds an option to set the default video quality.",
|
description = "Adds an option to set the default video quality.",
|
||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
OverrideQualityHookPatch::class,
|
OverrideQualityHookPatch::class,
|
||||||
OverrideSpeedHookPatch::class,
|
|
||||||
PlayerTypeHookPatch::class,
|
PlayerTypeHookPatch::class,
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
ShortsPlaybackPatch::class,
|
ShortsPlaybackPatch::class,
|
||||||
VideoIdPatch::class,
|
VideoIdPatch::class,
|
||||||
VideoIdWithoutShortsPatch::class
|
VideoInformationPatch::class
|
||||||
),
|
),
|
||||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||||
fingerprints = setOf(
|
fingerprints = setOf(
|
||||||
NewVideoQualityChangedFingerprint,
|
QualityChangedFromRecyclerViewFingerprint,
|
||||||
VideoQualitySetterFingerprint
|
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) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
|
||||||
NewVideoQualityChangedFingerprint.resultOrThrow().let {
|
// Remember video quality from recyclerview (litho view).
|
||||||
|
QualityChangedFromRecyclerViewFingerprint.resultOrThrow().let {
|
||||||
it.mutableMethod.apply {
|
it.mutableMethod.apply {
|
||||||
val index = it.scanResult.patternScanResult!!.startIndex
|
val index = it.scanResult.patternScanResult!!.startIndex
|
||||||
val qualityRegister = getInstruction<TwoRegisterInstruction>(index).registerA
|
val qualityRegister = getInstruction<TwoRegisterInstruction>(index).registerA
|
||||||
@ -55,7 +59,7 @@ object VideoQualityPatch : BaseBytecodePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoQualitySetterFingerprint.resultOrThrow().let {
|
QualitySetterFingerprint.resultOrThrow().let {
|
||||||
val onItemClickMethod =
|
val onItemClickMethod =
|
||||||
it.mutableClass.methods.find { method -> method.name == "onItemClick" }
|
it.mutableClass.methods.find { method -> method.name == "onItemClick" }
|
||||||
|
|
||||||
@ -69,10 +73,8 @@ object VideoQualityPatch : BaseBytecodePatch(
|
|||||||
} ?: throw PatchException("Failed to find onItemClick method")
|
} ?: throw PatchException("Failed to find onItemClick method")
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||||
VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||||
|
|
||||||
VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy arrays
|
* Copy arrays
|
||||||
@ -94,9 +96,4 @@ object VideoQualityPatch : BaseBytecodePatch(
|
|||||||
SettingsPatch.updatePatchStatus("Default video quality")
|
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.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.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.fingerprints.VideoEndFingerprint
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
|
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.UTILS_PATH
|
||||||
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_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.settings.SettingsPatch
|
||||||
import app.revanced.patches.youtube.utils.videocpn.VideoCpnPatch
|
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||||
import app.revanced.patches.youtube.video.speed.fingerprints.NewPlaybackSpeedChangedFingerprint
|
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.patches.youtube.video.speed.fingerprints.PlaybackSpeedInitializeFingerprint
|
||||||
|
import app.revanced.util.getTargetIndex
|
||||||
import app.revanced.util.patch.BaseBytecodePatch
|
import app.revanced.util.patch.BaseBytecodePatch
|
||||||
import app.revanced.util.resultOrThrow
|
import app.revanced.util.resultOrThrow
|
||||||
import app.revanced.util.updatePatchStatus
|
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.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object PlaybackSpeedPatch : BaseBytecodePatch(
|
object PlaybackSpeedPatch : BaseBytecodePatch(
|
||||||
name = "Default playback speed",
|
name = "Default playback speed",
|
||||||
description = "Adds an option to set the default playback speed.",
|
description = "Adds an option to set the default playback speed.",
|
||||||
dependencies = setOf(
|
dependencies = setOf(
|
||||||
OverrideSpeedHookPatch::class,
|
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
VideoCpnPatch::class
|
VideoInformationPatch::class
|
||||||
),
|
),
|
||||||
compatiblePackages = COMPATIBLE_PACKAGE,
|
compatiblePackages = COMPATIBLE_PACKAGE,
|
||||||
fingerprints = setOf(
|
fingerprints = setOf(
|
||||||
NewVideoQualityChangedFingerprint,
|
QualityChangedFromRecyclerViewFingerprint,
|
||||||
VideoEndFingerprint
|
VideoEndFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -40,26 +41,29 @@ object PlaybackSpeedPatch : BaseBytecodePatch(
|
|||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
|
|
||||||
NewVideoQualityChangedFingerprint.resultOrThrow().let { parentResult ->
|
PlaybackSpeedChangedFromRecyclerViewFingerprint.resolve(
|
||||||
NewPlaybackSpeedChangedFingerprint.also {
|
|
||||||
it.resolve(
|
|
||||||
context,
|
context,
|
||||||
parentResult.classDef
|
QualityChangedFromRecyclerViewFingerprint.resultOrThrow().classDef
|
||||||
)
|
)
|
||||||
}.resultOrThrow().let { result ->
|
|
||||||
arrayOf(result, OverrideSpeedHookPatch.playbackSpeedChangedResult).forEach {
|
val newMethod = PlaybackSpeedChangedFromRecyclerViewFingerprint.resultOrThrow().mutableMethod
|
||||||
it.mutableMethod.apply {
|
|
||||||
val index = it.scanResult.patternScanResult!!.endIndex
|
arrayOf(
|
||||||
val register = getInstruction<FiveRegisterInstruction>(index).registerD
|
newMethod,
|
||||||
|
speedSelectionInsertMethod
|
||||||
|
).forEach {
|
||||||
|
it.apply {
|
||||||
|
val speedSelectionValueInstructionIndex = getTargetIndex(Opcode.IGET)
|
||||||
|
val speedSelectionValueRegister =
|
||||||
|
getInstruction<TwoRegisterInstruction>(speedSelectionValueInstructionIndex).registerA
|
||||||
|
|
||||||
addInstruction(
|
addInstruction(
|
||||||
index,
|
speedSelectionValueInstructionIndex + 1,
|
||||||
"invoke-static {v$register}, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->userChangedSpeed(F)V"
|
"invoke-static {v$speedSelectionValueRegister}, " +
|
||||||
|
"$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->userSelectedPlaybackSpeed(F)V"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoEndFingerprint.resultOrThrow().let { parentResult ->
|
VideoEndFingerprint.resultOrThrow().let { parentResult ->
|
||||||
PlaybackSpeedInitializeFingerprint.also {
|
PlaybackSpeedInitializeFingerprint.also {
|
||||||
@ -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
|
* 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.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object NewPlaybackSpeedChangedFingerprint : MethodFingerprint(
|
internal object PlaybackSpeedChangedFromRecyclerViewFingerprint : MethodFingerprint(
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("L"),
|
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.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
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.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
internal object VideoIdWithoutShortsFingerprint : MethodFingerprint(
|
/**
|
||||||
|
* Renamed from VideoIdWithoutShortsFingerprint
|
||||||
|
*/
|
||||||
|
internal object VideoIdFingerprintBackgroundPlay : MethodFingerprint(
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED,
|
||||||
parameters = listOf("L"),
|
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
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user