mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-29 05:10:20 +02:00
refactor(YouTube/Video information): change invoke method
- Different methods are invoked depending on whether the video being played is a regular video or Shorts. - The following information is invoked in VideoInformation: Channel Id, Channel Name, Video Title, Video Length, LiveStream, Playlist Id. - Also, video time is invoked every 100ms, not 1000ms.
This commit is contained in:
parent
a71d1870c4
commit
e5c180ba84
@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
|
||||
@Suppress("unused")
|
||||
@ -14,13 +14,13 @@ object AutoCaptionsPatch : BaseBytecodePatch(
|
||||
dependencies = setOf(
|
||||
AutoCaptionsBytecodePatch::class,
|
||||
SettingsPatch::class,
|
||||
VideoIdPatch::class
|
||||
VideoInformationPatch::class
|
||||
),
|
||||
compatiblePackages = COMPATIBLE_PACKAGE
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$GENERAL_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
VideoInformationPatch.hookBackgroundPlay("$GENERAL_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
|
||||
/**
|
||||
* Add settings
|
||||
|
@ -53,7 +53,7 @@ object SpoofPlayerParameterPatch : BaseBytecodePatch(
|
||||
|
||||
// Hook the player parameters.
|
||||
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;Ljava/lang/String;Z)Ljava/lang/String;"
|
||||
)
|
||||
|
||||
// Force the seekbar time and chapters to always show up.
|
||||
|
@ -66,6 +66,7 @@ object SharedResourceIdPatch : ResourcePatch() {
|
||||
var ModernMiniPlayerForwardButton = -1L
|
||||
var ModernMiniPlayerRewindButton = -1L
|
||||
var MusicAppDeeplinkButtonView = -1L
|
||||
var NotificationBigPictureIconWidth = -1L
|
||||
var PanelSubHeader = -1L
|
||||
var PlayerCollapseButton = -1L
|
||||
var PosterArtWidthDefault = -1L
|
||||
@ -152,6 +153,7 @@ object SharedResourceIdPatch : ResourcePatch() {
|
||||
ModernMiniPlayerForwardButton = getId(ID, "modern_miniplayer_forward_button")
|
||||
ModernMiniPlayerRewindButton = getId(ID, "modern_miniplayer_rewind_button")
|
||||
MusicAppDeeplinkButtonView = getId(ID, "music_app_deeplink_button_view")
|
||||
NotificationBigPictureIconWidth = getId(DIMEN, "notification_big_picture_icon_width")
|
||||
PanelSubHeader = getId(ID, "panel_subheader")
|
||||
PlayerCollapseButton = getId(ID, "player_collapse_button")
|
||||
PosterArtWidthDefault = getId(DIMEN, "poster_art_width_default")
|
||||
|
@ -18,7 +18,6 @@ import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.Inset
|
||||
import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint
|
||||
import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.SegmentPlaybackControllerFingerprint
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceTypeReversed
|
||||
import app.revanced.util.getTargetIndexWithMethodReferenceName
|
||||
@ -35,7 +34,6 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
dependencies = [
|
||||
PlayerControlsPatch::class,
|
||||
SharedResourceIdPatch::class,
|
||||
VideoIdPatch::class,
|
||||
VideoInformationPatch::class
|
||||
]
|
||||
)
|
||||
@ -173,6 +171,6 @@ object SponsorBlockBytecodePatch : BytecodePatch(
|
||||
)
|
||||
|
||||
// Set current video id
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
VideoInformationPatch.hook("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
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.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
@ -18,18 +19,27 @@ import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.SHARED_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.ChannelIdFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.ChannelNameFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.OnPlaybackSpeedItemClickFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.PlaybackInitializationFingerprint
|
||||
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.VideoIdFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprintBackgroundPlay
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.VideoIdFingerprintShorts
|
||||
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.information.fingerprints.VideoTimeFingerprint
|
||||
import app.revanced.patches.youtube.video.information.fingerprints.VideoTitleFingerprint
|
||||
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||
import app.revanced.util.addFieldAndInstructions
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.getTargetIndexReversed
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
@ -37,6 +47,7 @@ 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.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
@ -53,27 +64,54 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
)
|
||||
object VideoInformationPatch : BytecodePatch(
|
||||
setOf(
|
||||
ChannelIdFingerprint,
|
||||
ChannelNameFingerprint,
|
||||
OnPlaybackSpeedItemClickFingerprint,
|
||||
OrganicPlaybackContextModelFingerprint,
|
||||
PlaybackInitializationFingerprint,
|
||||
PlaybackSpeedClassFingerprint,
|
||||
PlayerControllerSetTimeReferenceFingerprint,
|
||||
VideoEndFingerprint,
|
||||
VideoIdFingerprint,
|
||||
VideoIdFingerprintBackgroundPlay,
|
||||
VideoIdFingerprintShorts,
|
||||
VideoLengthFingerprint,
|
||||
VideoQualityListFingerprint,
|
||||
VideoQualityTextFingerprint
|
||||
VideoQualityTextFingerprint,
|
||||
VideoTitleFingerprint,
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"$SHARED_PATH/VideoInformation;"
|
||||
|
||||
private const val PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR =
|
||||
"Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"
|
||||
|
||||
private const val REGISTER_PLAYER_RESPONSE_MODEL = 8
|
||||
|
||||
private const val REGISTER_CHANNEL_ID = 0
|
||||
private const val REGISTER_CHANNEL_NAME = 1
|
||||
private const val REGISTER_VIDEO_ID = 2
|
||||
private const val REGISTER_VIDEO_TITLE = 3
|
||||
private const val REGISTER_VIDEO_LENGTH = 4
|
||||
private const val REGISTER_VIDEO_LENGTH_DUMMY = 5
|
||||
private const val REGISTER_VIDEO_IS_LIVE = 6
|
||||
|
||||
private lateinit var channelIdMethodCall: String
|
||||
private lateinit var channelNameMethodCall: String
|
||||
private lateinit var videoIdMethodCall: String
|
||||
private lateinit var videoTitleMethodCall: String
|
||||
private lateinit var videoLengthMethodCall: String
|
||||
private lateinit var videoIsLiveMethodCall: String
|
||||
|
||||
private lateinit var videoInformationMethod: MutableMethod
|
||||
private lateinit var backgroundVideoInformationMethod: MutableMethod
|
||||
private lateinit var shortsVideoInformationMethod: MutableMethod
|
||||
|
||||
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
|
||||
private lateinit var videoTimeMethod: MutableMethod
|
||||
private var videoTimeIndex = 1
|
||||
|
||||
// Used by other patches.
|
||||
internal lateinit var speedSelectionInsertMethod: MutableMethod
|
||||
@ -83,6 +121,10 @@ object VideoInformationPatch : BytecodePatch(
|
||||
val videoInformationMutableClass = context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR)!!.mutableClass
|
||||
|
||||
VideoEndFingerprint.resultOrThrow().let {
|
||||
|
||||
// resolve video time fingerprint
|
||||
VideoTimeFingerprint.resolve(context, it.classDef)
|
||||
|
||||
playerConstructorMethod =
|
||||
it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) }
|
||||
|
||||
@ -149,12 +191,84 @@ object VideoInformationPatch : BytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video information
|
||||
*/
|
||||
channelIdMethodCall = ChannelIdFingerprint.getMethodName("Ljava/lang/String;")
|
||||
channelNameMethodCall = ChannelNameFingerprint.getMethodName("Ljava/lang/String;")
|
||||
videoIdMethodCall = VideoIdFingerprint.getMethodName("Ljava/lang/String;")
|
||||
videoTitleMethodCall = VideoTitleFingerprint.getMethodName("Ljava/lang/String;")
|
||||
videoLengthMethodCall = VideoLengthFingerprint.getMethodName("J")
|
||||
videoIsLiveMethodCall = ChannelIdFingerprint.getMethodName("Z")
|
||||
|
||||
PlaybackInitializationFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_DIRECT
|
||||
&& getReference<MethodReference>()?.returnType == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
||||
} + 1
|
||||
if (targetIndex == 0) throw PatchException("Could not find instruction index.")
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
targetIndex + 1,
|
||||
"invoke-direct {p0, v$targetRegister}, $definingClass->setVideoInformation($PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR)V"
|
||||
)
|
||||
|
||||
videoInformationMethod = getVideoInformationMethod()
|
||||
it.mutableClass.methods.add(videoInformationMethod)
|
||||
|
||||
hook("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoInformation(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
}
|
||||
}
|
||||
|
||||
VideoIdFingerprintBackgroundPlay.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_INTERFACE
|
||||
&& getReference<MethodReference>()?.definingClass == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
||||
}
|
||||
if (targetIndex < 0) throw PatchException("Could not find instruction index.")
|
||||
val targetRegister = getInstruction<FiveRegisterInstruction>(targetIndex).registerC
|
||||
|
||||
addInstruction(
|
||||
targetIndex,
|
||||
"invoke-direct {p0, v$targetRegister}, $definingClass->setVideoInformation($PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR)V"
|
||||
)
|
||||
|
||||
backgroundVideoInformationMethod = getVideoInformationMethod()
|
||||
it.mutableClass.methods.add(backgroundVideoInformationMethod)
|
||||
}
|
||||
}
|
||||
|
||||
VideoIdFingerprintShorts.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_INTERFACE
|
||||
&& getReference<MethodReference>()?.definingClass == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
||||
}
|
||||
if (targetIndex < 0) throw PatchException("Could not find instruction index.")
|
||||
val targetRegister = getInstruction<FiveRegisterInstruction>(targetIndex).registerC
|
||||
|
||||
addInstruction(
|
||||
targetIndex,
|
||||
"invoke-direct {p0, v$targetRegister}, $definingClass->setVideoInformation($PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR)V"
|
||||
)
|
||||
|
||||
shortsVideoInformationMethod = getVideoInformationMethod()
|
||||
it.mutableClass.methods.add(shortsVideoInformationMethod)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current video time method
|
||||
*/
|
||||
PlayerControllerSetTimeReferenceFingerprint.resultOrThrow().let {
|
||||
videoTimeConstructorMethod =
|
||||
it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex)
|
||||
VideoTimeFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
videoTimeMethod = this
|
||||
addInstruction(
|
||||
0,
|
||||
"move-wide/from16 v0, p5"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,40 +276,15 @@ object VideoInformationPatch : BytecodePatch(
|
||||
*/
|
||||
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;")
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerResponseParameter(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;")
|
||||
|
||||
/**
|
||||
* Hook current playback speed
|
||||
@ -346,12 +435,6 @@ object VideoInformationPatch : BytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
@ -375,15 +458,97 @@ object VideoInformationPatch : BytecodePatch(
|
||||
* @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"
|
||||
videoTimeMethod.addInstruction(
|
||||
videoTimeIndex++,
|
||||
"invoke-static { v0, v1 }, $targetMethodClass->$targetMethodName(J)V"
|
||||
)
|
||||
|
||||
internal fun cpnHook(descriptor: String) =
|
||||
videoCpnConstructorMethod.insert(
|
||||
videoCpnConstructorInsertIndex++,
|
||||
"p1, p2",
|
||||
private fun MethodFingerprint.getMethodName(returnType : String) :String {
|
||||
resultOrThrow().mutableMethod.apply {
|
||||
val targetIndex = indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_INTERFACE
|
||||
&& getReference<MethodReference>()?.definingClass == PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR
|
||||
&& getReference<MethodReference>()?.returnType == returnType
|
||||
}
|
||||
if (targetIndex < 0) throw PatchException("Could not find instruction index.")
|
||||
val targetReference = getInstruction<ReferenceInstruction>(targetIndex).reference
|
||||
|
||||
return "invoke-interface {v${REGISTER_PLAYER_RESPONSE_MODEL}}, $targetReference"
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableMethod.getVideoInformationMethod(): MutableMethod =
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
"setVideoInformation",
|
||||
listOf(ImmutableMethodParameter(PLAYER_RESPONSE_MODEL_CLASS_DESCRIPTOR, annotations, null)),
|
||||
"V",
|
||||
AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
annotations,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
9, """
|
||||
$channelIdMethodCall
|
||||
move-result-object v$REGISTER_CHANNEL_ID
|
||||
$channelNameMethodCall
|
||||
move-result-object v$REGISTER_CHANNEL_NAME
|
||||
$videoIdMethodCall
|
||||
move-result-object v$REGISTER_VIDEO_ID
|
||||
$videoTitleMethodCall
|
||||
move-result-object v$REGISTER_VIDEO_TITLE
|
||||
$videoLengthMethodCall
|
||||
move-result-wide v$REGISTER_VIDEO_LENGTH
|
||||
$videoIsLiveMethodCall
|
||||
move-result v$REGISTER_VIDEO_IS_LIVE
|
||||
return-void
|
||||
""".toInstructions(),
|
||||
null,
|
||||
null
|
||||
)
|
||||
).toMutable()
|
||||
|
||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||
addInstruction(insertIndex, "invoke-static/range { $register }, $descriptor")
|
||||
|
||||
/**
|
||||
* This method is invoked on both regular videos and Shorts.
|
||||
*/
|
||||
internal fun hook(descriptor: String) =
|
||||
videoInformationMethod.apply {
|
||||
val index = implementation!!.instructions.size - 1
|
||||
|
||||
insert(
|
||||
index,
|
||||
"v${REGISTER_CHANNEL_ID} .. v${REGISTER_VIDEO_IS_LIVE}",
|
||||
descriptor
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked only in regular videos.
|
||||
*/
|
||||
internal fun hookBackgroundPlay(descriptor: String) =
|
||||
backgroundVideoInformationMethod.apply {
|
||||
val index = implementation!!.instructions.size - 1
|
||||
|
||||
insert(
|
||||
index,
|
||||
"v${REGISTER_CHANNEL_ID} .. v${REGISTER_VIDEO_IS_LIVE}",
|
||||
descriptor
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked only in shorts videos.
|
||||
*/
|
||||
internal fun hookShorts(descriptor: String) =
|
||||
shortsVideoInformationMethod.apply {
|
||||
val index = implementation!!.instructions.size - 1
|
||||
|
||||
insert(
|
||||
index,
|
||||
"v${REGISTER_CHANNEL_ID} .. v${REGISTER_VIDEO_IS_LIVE}",
|
||||
descriptor
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object ChannelIdFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Ljava/lang/Object;"),
|
||||
strings = listOf("com.google.android.apps.youtube.mdx.watch.LAST_MEALBAR_PROMOTED_LIVE_FEED_CHANNELS")
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object ChannelNameFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
strings = listOf(
|
||||
"setMetadata may only be called once",
|
||||
"Person",
|
||||
)
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object PlaybackInitializationFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
strings = listOf("play() called when the player wasn\'t loaded.")
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object PlayerControllerSetTimeReferenceFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_DIRECT_RANGE,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf("Media progress reported outside media playback: ")
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object VideoIdFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
strings = listOf("Failed to download video (IllegalStateException): %s")
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.youtube.video.videoid.fingerprints
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
@ -0,0 +1,19 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.util.fingerprint.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
/**
|
||||
* This fingerprint is compatible with all versions of YouTube starting from v18.29.38 to supported versions.
|
||||
* This method is invoked only in Shorts.
|
||||
* Accurate video information is invoked even when the user moves Shorts upward or downward.
|
||||
*/
|
||||
internal object VideoIdFingerprintShorts : LiteralValueFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
literalSupplier = { 45365621 }
|
||||
)
|
@ -1,18 +1,11 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.util.fingerprint.LiteralValueFingerprint
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object VideoLengthFingerprint : LiteralValueFingerprint(
|
||||
internal object VideoLengthFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
),
|
||||
literalSupplier = { 45388753 }
|
||||
strings = listOf("Gaplessly transitioning away from an Ad before it ends.")
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object VideoTimeFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L", "I", "J", "J", "J", "J")
|
||||
)
|
@ -0,0 +1,13 @@
|
||||
package app.revanced.patches.youtube.video.information.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.NotificationBigPictureIconWidth
|
||||
import app.revanced.util.fingerprint.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object VideoTitleFingerprint : LiteralValueFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
literalSupplier = { NotificationBigPictureIconWidth }
|
||||
)
|
@ -67,7 +67,6 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
DeviceDimensionsModelToStringFingerprint,
|
||||
HDRCapabilityFingerprint,
|
||||
PlaybackSpeedChangedFromRecyclerViewFingerprint,
|
||||
PlaybackSpeedInitializeFingerprint,
|
||||
QualityChangedFromRecyclerViewFingerprint,
|
||||
QualityMenuViewInflateFingerprint,
|
||||
QualitySetterFingerprint,
|
||||
@ -163,7 +162,7 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
VideoInformationPatch.cpnHook("$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Z)V")
|
||||
VideoInformationPatch.hookBackgroundPlay("$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
|
||||
context.updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "RememberPlaybackSpeed")
|
||||
|
||||
@ -195,8 +194,8 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
} ?: throw PatchException("Failed to find onItemClick method")
|
||||
}
|
||||
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||
VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||
VideoInformationPatch.hook("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
VideoInformationPatch.hookBackgroundPlay("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
|
||||
// endregion
|
||||
|
||||
@ -212,7 +211,7 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
addInstruction(
|
||||
insertIndex + 1,
|
||||
"invoke-static { v$insertRegister }, " +
|
||||
"$INTEGRATIONS_RESTORE_OLD_VIDEO_QUALITY_MENU_CLASS_DESCRIPTOR->showOldVideoQualityMenu(Landroid/widget/ListView;)V"
|
||||
"$INTEGRATIONS_RESTORE_OLD_VIDEO_QUALITY_MENU_CLASS_DESCRIPTOR->restoreOldVideoQualityMenu(Landroid/widget/ListView;)V"
|
||||
)
|
||||
}
|
||||
val onItemClickMethod =
|
||||
@ -229,7 +228,7 @@ object VideoPlaybackPatch : BaseBytecodePatch(
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
invoke-static {}, $INTEGRATIONS_RESTORE_OLD_VIDEO_QUALITY_MENU_CLASS_DESCRIPTOR->showOldVideoQualityMenu()Z
|
||||
invoke-static {}, $INTEGRATIONS_RESTORE_OLD_VIDEO_QUALITY_MENU_CLASS_DESCRIPTOR->restoreOldVideoQualityMenu()Z
|
||||
move-result v$insertRegister
|
||||
if-nez v$insertRegister, :show
|
||||
""", ExternalLabel("show", getInstruction(jumpIndex))
|
||||
|
@ -57,12 +57,12 @@ object PlayerResponseMethodHookPatch :
|
||||
val instruction =
|
||||
if (shouldApplyNewMethod)
|
||||
"""
|
||||
invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_PLAYER_PARAMETER, v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
|
||||
invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_PLAYER_PARAMETER, v$PARAMETER_PLAYLIST_ID, 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
|
||||
invoke-static {p$PARAMETER_VIDEO_ID, p$PARAMETER_PLAYER_PARAMETER, p$PARAMETER_PLAYLIST_ID, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook
|
||||
move-result-object p$PARAMETER_PLAYER_PARAMETER
|
||||
"""
|
||||
|
||||
|
@ -10,11 +10,8 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
@ -22,19 +19,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
dependencies = [PlayerResponseMethodHookPatch::class],
|
||||
)
|
||||
object VideoIdPatch : BytecodePatch(
|
||||
setOf(
|
||||
VideoIdParentFingerprint,
|
||||
VideoIdFingerprintBackgroundPlay
|
||||
)
|
||||
setOf(VideoIdParentFingerprint)
|
||||
) {
|
||||
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) {
|
||||
|
||||
/**
|
||||
@ -59,14 +49,6 @@ object VideoIdPatch : BytecodePatch(
|
||||
videoIdInsertIndex = index
|
||||
videoIdRegister = register
|
||||
}
|
||||
|
||||
VideoIdFingerprintBackgroundPlay.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
backgroundPlaybackMethod = this
|
||||
backgroundPlaybackInsertIndex = getTargetIndex(Opcode.INVOKE_INTERFACE) + 2
|
||||
backgroundPlaybackVideoIdRegister = getInstruction<OneRegisterInstruction>(backgroundPlaybackInsertIndex - 1).registerA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,23 +69,6 @@ object VideoIdPatch : BytecodePatch(
|
||||
"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.
|
||||
@ -120,8 +85,7 @@ object VideoIdPatch : BytecodePatch(
|
||||
* 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.
|
||||
* For most use cases, you probably want to use [hookVideoId] instead.
|
||||
*
|
||||
* Be aware, this can be called multiple times for the same video id.
|
||||
*
|
||||
|
@ -1041,7 +1041,7 @@ Limitation: Official headers in search results will be hidden."</string>
|
||||
<string name="revanced_skip_preloaded_buffer_title">Skip preloaded buffer</string>
|
||||
<string name="revanced_skip_preloaded_buffer_summary">"Skip preloaded buffer at video start to bypass default video quality enforcement delay.
|
||||
|
||||
• When the video starts, there is a delay of approximately 0.7 seconds, but the default video quality is applied immediately.
|
||||
• When the video starts, there is a delay of approximately 0.3 seconds, but the default video quality is applied immediately.
|
||||
• Does not apply to HDR videos, live stream videos, videos shorter than 15 seconds."</string>
|
||||
<string name="revanced_skip_preloaded_buffer_toast_title">Show a toast when skipped</string>
|
||||
<string name="revanced_skip_preloaded_buffer_toast_summary_on">Toast is shown.</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user