refactor(YouTube/Video information): include video quality

This commit is contained in:
inotia00
2024-04-06 05:40:59 +09:00
parent 7ba43b6f4c
commit c17709319a
11 changed files with 123 additions and 195 deletions

View File

@ -10,7 +10,6 @@ import app.revanced.util.getTargetIndexReversed
import app.revanced.util.getWalkerMethod
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
object AlwaysRepeatPatch : BytecodePatch(

View File

@ -6,7 +6,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patches.youtube.utils.fingerprints.TotalTimeFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.SEEKBAR_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
@ -21,7 +20,6 @@ object AppendTimeStampInformationPatch : BaseBytecodePatch(
name = "Append time stamps information",
description = "Adds an option to add the current video quality or playback speed in brackets next to the current time.",
dependencies = setOf(
OverrideQualityHookPatch::class,
SettingsPatch::class,
SharedResourceIdPatch::class,
VideoInformationPatch::class

View File

@ -1,119 +0,0 @@
package app.revanced.patches.youtube.utils.overridequality
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.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
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.overridequality.fingerprints.VideoQualityListFingerprint
import app.revanced.patches.youtube.utils.overridequality.fingerprints.VideoQualityPatchFingerprint
import app.revanced.patches.youtube.utils.overridequality.fingerprints.VideoQualityTextFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.QualityAuto
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableField
import com.android.tools.smali.dexlib2.util.MethodUtil
@Patch(dependencies = [SharedResourceIdPatch::class])
object OverrideQualityHookPatch : BytecodePatch(
setOf(
VideoQualityListFingerprint,
VideoQualityPatchFingerprint,
VideoQualityTextFingerprint
)
) {
private const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoQualityPatch;"
private const val INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR =
"$INTEGRATIONS_PATH/utils/VideoUtils;"
private lateinit var objectClass: String
private lateinit var objectMethod: String
override fun execute(context: BytecodeContext) {
VideoQualityListFingerprint.resultOrThrow().let {
val constructorMethod =
it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) }
val overrideMethod =
it.mutableClass.methods.find { method -> method.parameterTypes.first() == "I" }
objectClass = it.method.definingClass
objectMethod = overrideMethod?.name
?: throw PatchException("Failed to find hook method")
constructorMethod.apply {
addInstruction(
2,
"sput-object p0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qualityClass:$objectClass"
)
}
it.mutableMethod.apply {
val listIndex = it.scanResult.patternScanResult!!.startIndex
val listRegister = getInstruction<FiveRegisterInstruction>(listIndex).registerD
val qualityAutoIndex = getWideLiteralInstructionIndex(QualityAuto) + 2
val qualityAutoRegister =
getInstruction<OneRegisterInstruction>(qualityAutoIndex).registerA
addInstruction(
listIndex,
"invoke-static {v$listRegister}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQualityList([Ljava/lang/Object;)V"
)
addInstruction(
qualityAutoIndex + 1,
"sput-object v$qualityAutoRegister, $INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR->qualityAutoString:Ljava/lang/String;"
)
}
}
VideoQualityPatchFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
it.mutableClass.staticFields.add(
ImmutableField(
definingClass,
"qualityClass",
objectClass,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
annotations,
null
).toMutable()
)
addInstructions(
0, """
sget-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qualityClass:$objectClass
invoke-virtual {v0, p0}, $objectClass->$objectMethod(I)V
"""
)
}
}
VideoQualityTextFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val textIndex = it.scanResult.patternScanResult!!.endIndex
val textRegister = getInstruction<TwoRegisterInstruction>(textIndex).registerA
addInstruction(
textIndex + 1,
"sput-object v$textRegister, $INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR->currentQuality:Ljava/lang/String;"
)
}
}
}
}

View File

@ -1,16 +0,0 @@
package app.revanced.patches.youtube.utils.overridequality.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
import com.android.tools.smali.dexlib2.AccessFlags
internal object VideoQualityPatchFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("I"),
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "$VIDEO_PATH/VideoQualityPatch;"
&& methodDef.name == "overrideQuality"
}
)

View File

@ -6,11 +6,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
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.PlayerButtonsResourcesFingerprint
import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
import app.revanced.patches.youtube.utils.playercontrols.fingerprints.BottomControlsInflateFingerprint
import app.revanced.patches.youtube.utils.playercontrols.fingerprints.ControlsLayoutInflateFingerprint
import app.revanced.patches.youtube.utils.fingerprints.PlayerButtonsResourcesFingerprint
import app.revanced.patches.youtube.utils.playercontrols.fingerprints.PlayerButtonsVisibilityFingerprint
import app.revanced.patches.youtube.utils.playercontrols.fingerprints.PlayerControlsPatchFingerprint
import app.revanced.patches.youtube.utils.playercontrols.fingerprints.PlayerControlsVisibilityFingerprint

View File

@ -2,12 +2,12 @@ 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.PatchException
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
@ -18,11 +18,13 @@ import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextMod
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.utils.resourceid.SharedResourceIdPatch
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.information.fingerprints.VideoQualityListFingerprint
import app.revanced.patches.youtube.video.information.fingerprints.VideoQualityTextFingerprint
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.getTargetIndex
@ -31,8 +33,10 @@ 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.FiveRegisterInstruction
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.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableField
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
@ -44,6 +48,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
dependencies = [
PlayerResponseMethodHookPatch::class,
PlayerTypeHookPatch::class,
SharedResourceIdPatch::class,
VideoIdPatch::class
]
)
@ -54,8 +59,9 @@ object VideoInformationPatch : BytecodePatch(
PlaybackSpeedClassFingerprint,
PlayerControllerSetTimeReferenceFingerprint,
VideoEndFingerprint,
VideoInformationPatchFingerprint,
VideoLengthFingerprint
VideoLengthFingerprint,
VideoQualityListFingerprint,
VideoQualityTextFingerprint
)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
@ -169,8 +175,10 @@ object VideoInformationPatch : BytecodePatch(
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.PlayerParameterBeforeVideoId(
"$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerResponseParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;")
val videoInformationMutableClass = context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
/**
* Hook the user playback speed selection
* Hook current playback speed
*/
OnPlaybackSpeedItemClickFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
@ -186,6 +194,7 @@ object VideoInformationPatch : BytecodePatch(
val setPlaybackSpeedMethodReference =
getInstruction<ReferenceInstruction>(speedSelectionValueInstructionIndex + 2).reference.toString()
// add override playback speed method
it.mutableClass.methods.add(
ImmutableMethod(
definingClass,
@ -217,8 +226,8 @@ object VideoInformationPatch : BytecodePatch(
).toMutable()
)
// set current playback speed
val walkerMethod = getWalkerMethod(context, speedSelectionValueInstructionIndex + 2)
walkerMethod.apply {
addInstruction(
this.implementation!!.instructions.size - 1,
@ -233,6 +242,8 @@ object VideoInformationPatch : BytecodePatch(
val index = result.scanResult.patternScanResult!!.endIndex
val register = getInstruction<OneRegisterInstruction>(index).registerA
val playbackSpeedClass = this.returnType
// set playback speed class
replaceInstruction(
index,
"sput-object v$register, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackSpeedClass:$playbackSpeedClass"
@ -242,31 +253,109 @@ object VideoInformationPatch : BytecodePatch(
"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()
)
videoInformationMutableClass.methods.single { method ->
method.name == "overridePlaybackSpeed"
}.apply {
// add playback speed class
videoInformationMutableClass.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
"""
)
}
// call override playback speed method
addInstructionsWithLabels(
0, """
sget-object v0, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackSpeedClass:$playbackSpeedClass
if-eqz v0, :ignore
invoke-virtual {v0, p0}, $playbackSpeedClass->overridePlaybackSpeed(F)V
:ignore
return-void
"""
)
}
}
}
/**
* Hook current video quality
*/
VideoQualityListFingerprint.resultOrThrow().let {
val constructorMethod =
it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) }
val overrideMethod =
it.mutableClass.methods.find { method -> method.parameterTypes.first() == "I" }
val videoQualityClass = it.method.definingClass
val videoQualityMethodName = overrideMethod?.name
?: throw PatchException("Failed to find hook method")
// set video quality class
constructorMethod.apply {
addInstruction(
2,
"sput-object p0, $INTEGRATIONS_CLASS_DESCRIPTOR->videoQualityClass:$videoQualityClass"
)
}
// set video quality array
it.mutableMethod.apply {
val listIndex = it.scanResult.patternScanResult!!.startIndex
val listRegister = getInstruction<FiveRegisterInstruction>(listIndex).registerD
addInstruction(
listIndex,
"invoke-static {v$listRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoQualityList([Ljava/lang/Object;)V"
)
}
videoInformationMutableClass.methods.single { method ->
method.name == "overrideVideoQuality"
}.apply {
// add video quality class
videoInformationMutableClass.staticFields.add(
ImmutableField(
definingClass,
"videoQualityClass",
videoQualityClass,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
annotations,
null
).toMutable()
)
// call override video quality method
addInstructionsWithLabels(
0, """
sget-object v0, $INTEGRATIONS_CLASS_DESCRIPTOR->videoQualityClass:$videoQualityClass
if-eqz v0, :ignore
invoke-virtual {v0, p0}, $videoQualityClass->$videoQualityMethodName(I)V
:ignore
return-void
"""
)
}
}
// set current video quality
VideoQualityTextFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val textIndex = it.scanResult.patternScanResult!!.endIndex
val textRegister = getInstruction<TwoRegisterInstruction>(textIndex).registerA
addInstruction(
textIndex + 1,
"invoke-static {v$textRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoQuality(Ljava/lang/String;)V"
)
}
}
}
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =

View File

@ -1,16 +0,0 @@
package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
import com.android.tools.smali.dexlib2.AccessFlags
internal object VideoInformationPatchFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("F"),
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "$VIDEO_PATH/VideoInformation;"
&& methodDef.name == "overridePlaybackSpeed"
}
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.utils.overridequality.fingerprints
package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.QualityAuto
import app.revanced.util.fingerprint.LiteralValueFingerprint

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.utils.overridequality.fingerprints
package app.revanced.patches.youtube.video.information.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint

View File

@ -2,14 +2,12 @@ package app.revanced.patches.youtube.video.quality
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.youtube.utils.fingerprints.QualityChangedFromRecyclerViewFingerprint
import app.revanced.patches.youtube.utils.fingerprints.QualitySetterFingerprint
import app.revanced.patches.youtube.utils.fix.shortsplayback.ShortsPlaybackPatch
import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH
import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts
@ -18,14 +16,12 @@ import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.copyXmlNode
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Suppress("unused")
object VideoQualityPatch : BaseBytecodePatch(
name = "Default video quality",
description = "Adds an option to set the default video quality.",
dependencies = setOf(
OverrideQualityHookPatch::class,
PlayerTypeHookPatch::class,
SettingsPatch::class,
ShortsPlaybackPatch::class,
@ -49,11 +45,10 @@ object VideoQualityPatch : BaseBytecodePatch(
QualityChangedFromRecyclerViewFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val index = it.scanResult.patternScanResult!!.startIndex
val qualityRegister = getInstruction<TwoRegisterInstruction>(index).registerA
addInstruction(
index + 1,
"invoke-static {v$qualityRegister}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
"invoke-static {}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userSelectedVideoQuality()V"
)
}
@ -64,11 +59,9 @@ object VideoQualityPatch : BaseBytecodePatch(
it.mutableClass.methods.find { method -> method.name == "onItemClick" }
onItemClickMethod?.apply {
val listItemIndexParameter = 3
addInstruction(
0,
"invoke-static {p$listItemIndexParameter}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQualityIndex(I)V"
"invoke-static {}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userSelectedVideoQuality()V"
)
} ?: throw PatchException("Failed to find onItemClick method")
}

View File

@ -8,10 +8,10 @@ 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.VideoIdFingerprint
import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdFingerprintBackgroundPlay
import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdParentFingerprint
import app.revanced.util.getTargetIndex
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode