fix(YouTube Music/SponsorBlock): when the app is in the background, segments are not fetched

This commit is contained in:
inotia00
2023-11-09 15:48:57 +09:00
parent 1e736768de
commit 24ecd60862
9 changed files with 147 additions and 42 deletions

View File

@ -9,7 +9,7 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.player.replace.fingerprints.CastButtonContainerFingerprint
import app.revanced.patches.music.player.replace.fingerprints.PlaybackStartDescriptorFingerprint
import app.revanced.patches.music.utils.playerresponse.PlayerResponsePatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.PlayerCastMediaRouteButton
import app.revanced.patches.music.utils.settings.SettingsPatch
@ -32,6 +32,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
name = "Replace cast button",
description = "Replace the cast button in the player with the open music button.",
dependencies = [
PlayerResponsePatch::class,
SettingsPatch::class,
SharedResourceIdPatch::class,
VideoTypeHookPatch::class
@ -51,10 +52,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
)
@Suppress("unused")
object ReplaceCastButtonPatch : BytecodePatch(
setOf(
CastButtonContainerFingerprint,
PlaybackStartDescriptorFingerprint
)
setOf(CastButtonContainerFingerprint)
) {
override fun execute(context: BytecodeContext) {
@ -96,21 +94,11 @@ object ReplaceCastButtonPatch : BytecodePatch(
}
} ?: throw CastButtonContainerFingerprint.exception
PlaybackStartDescriptorFingerprint.result?.let {
it.mutableMethod.apply {
val videoIdRegister = 1
val playlistIdRegister = 4
val playlistIndexRegister = 5
addInstruction(
0,
"invoke-static {p$videoIdRegister, p$playlistIdRegister, p$playlistIndexRegister}, " +
"$MUSIC_UTILS_PATH/CheckMusicVideoPatch;" +
"->" +
"playbackStart(Ljava/lang/String;Ljava/lang/String;I)V"
)
}
} ?: throw PlaybackStartDescriptorFingerprint.exception
PlayerResponsePatch.injectPlaylistCall(
"$MUSIC_UTILS_PATH/CheckMusicVideoPatch;" +
"->" +
"playbackStart(Ljava/lang/String;Ljava/lang/String;I)V"
)
arrayOf(
ResourceUtils.ResourceGroup(

View File

@ -0,0 +1,47 @@
package app.revanced.patches.music.utils.playerresponse
import app.revanced.extensions.exception
import app.revanced.patcher.data.BytecodeContext
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.music.utils.playerresponse.fingerprints.PlaybackStartDescriptorFingerprint
object PlayerResponsePatch : BytecodePatch(
setOf(PlaybackStartDescriptorFingerprint)
) {
private const val VIDEO_ID_PARAMETER = 1
private const val PLAYLIST_ID_PARAMETER = 4
private const val PLAYLIST_INDEX_PARAMETER = 5
private const val VIDEO_IS_OPENING_OR_PLAYING_PARAMETER = 12
private lateinit var insertMethod: MutableMethod
internal fun injectCall(
methodDescriptor: String
) {
insertMethod.addInstructions(
0, // move-result-object offset
"invoke-static {p$VIDEO_ID_PARAMETER, p$VIDEO_IS_OPENING_OR_PLAYING_PARAMETER}, $methodDescriptor"
)
}
internal fun injectPlaylistCall(
methodDescriptor: String
) {
insertMethod.addInstructions(
0, // move-result-object offset
"invoke-static {p$VIDEO_ID_PARAMETER, p$PLAYLIST_ID_PARAMETER, p$PLAYLIST_INDEX_PARAMETER}, $methodDescriptor"
)
}
override fun execute(context: BytecodeContext) {
PlaybackStartDescriptorFingerprint.result?.let {
insertMethod = it.mutableMethod
} ?: throw PlaybackStartDescriptorFingerprint.exception
}
}

View File

@ -1,4 +1,4 @@
package app.revanced.patches.music.player.replace.fingerprints
package app.revanced.patches.music.utils.playerresponse.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint

View File

@ -8,6 +8,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
import app.revanced.patches.music.utils.playerresponse.PlayerResponsePatch
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints.MusicPlaybackControlsTimeBarDrawFingerprint
import app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints.MusicPlaybackControlsTimeBarOnMeasureFingerprint
@ -23,6 +24,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch(
dependencies = [
PlayerResponsePatch::class,
SharedResourceIdPatch::class,
VideoInformationPatch::class
]
@ -34,6 +36,10 @@ object SponsorBlockBytecodePatch : BytecodePatch(
SeekBarConstructorFingerprint
)
) {
private const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR =
"Lapp/revanced/music/sponsorblock/SegmentPlaybackController;"
private lateinit var rectangleFieldName: String
override fun execute(context: BytecodeContext) {
/**
@ -44,10 +50,6 @@ object SponsorBlockBytecodePatch : BytecodePatch(
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
"setVideoTime"
)
onCreateHook(
INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR,
"initialize"
)
}
@ -163,11 +165,8 @@ object SponsorBlockBytecodePatch : BytecodePatch(
/**
* Set current video id
*/
PlayerResponsePatch.injectCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;Z)V")
VideoInformationPatch.injectBackgroundPlaybackCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
VideoInformationPatch.injectCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
}
private const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR =
"Lapp/revanced/music/sponsorblock/SegmentPlaybackController;"
lateinit var rectangleFieldName: String
}

View File

@ -26,7 +26,8 @@ object VideoTypeHookPatch : BytecodePatch(
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 3
val referenceIndex = insertIndex + 1
val referenceInstruction = getInstruction<ReferenceInstruction>(referenceIndex).reference
val referenceInstruction =
getInstruction<ReferenceInstruction>(referenceIndex).reference
addInstructionsWithLabels(
insertIndex, """

View File

@ -12,9 +12,10 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.video.information.fingerprints.BackgroundPlaybackVideoIdFingerprint
import app.revanced.patches.music.video.information.fingerprints.BackgroundPlaybackVideoIdParentFingerprint
import app.revanced.patches.music.video.information.fingerprints.PlayerControllerSetTimeReferenceFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoEndFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoIdFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoIdParentFingerprint
import app.revanced.patches.music.video.information.fingerprints.VideoLengthFingerprint
import app.revanced.util.integrations.Constants.MUSIC_VIDEO_PATH
@ -31,6 +32,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
@Patch(dependencies = [SharedResourceIdPatch::class])
object VideoInformationPatch : BytecodePatch(
setOf(
BackgroundPlaybackVideoIdParentFingerprint,
PlayerControllerSetTimeReferenceFingerprint,
SeekBarConstructorFingerprint,
VideoEndFingerprint,
@ -40,19 +42,31 @@ object VideoInformationPatch : BytecodePatch(
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$MUSIC_VIDEO_PATH/VideoInformation;"
private var backgroundPlaybackInsertIndex = 0
private var offset = 0
private var playerInitInsertIndex = 4
private var timeInitInsertIndex = 2
private var videoIdIndex = 0
private var backgroundPlaybackVideoIdRegister = 0
private var videoIdRegister: Int = 0
private lateinit var backgroundPlaybackMethod: MutableMethod
private lateinit var videoIdMethod: MutableMethod
private lateinit var playerInitMethod: MutableMethod
private lateinit var timeMethod: MutableMethod
lateinit var rectangleFieldName: String
internal fun injectBackgroundPlaybackCall(
methodDescriptor: String
) {
backgroundPlaybackMethod.addInstructions(
backgroundPlaybackInsertIndex, // move-result-object offset
"invoke-static {v$backgroundPlaybackVideoIdRegister}, $methodDescriptor"
)
}
/**
* 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;`
@ -182,24 +196,60 @@ object VideoInformationPatch : BytecodePatch(
/**
* Inject call for video id
* Inject call for background playback video id
*/
VideoIdParentFingerprint.result?.let { parentResult ->
VideoIdFingerprint.also {
BackgroundPlaybackVideoIdParentFingerprint.result?.let { parentResult ->
BackgroundPlaybackVideoIdFingerprint.also {
it.resolve(
context,
parentResult.classDef
)
}.result?.let {
it.mutableMethod.apply {
videoIdMethod = this
videoIdIndex = it.scanResult.patternScanResult!!.endIndex
videoIdRegister = getInstruction<OneRegisterInstruction>(videoIdIndex).registerA
backgroundPlaybackMethod = this
backgroundPlaybackInsertIndex = it.scanResult.patternScanResult!!.endIndex
backgroundPlaybackVideoIdRegister =
getInstruction<OneRegisterInstruction>(backgroundPlaybackInsertIndex).registerA
backgroundPlaybackInsertIndex++
}
offset++ // offset so setVideoId is called before any injected call
} ?: throw VideoIdFingerprint.exception
} ?: throw BackgroundPlaybackVideoIdFingerprint.exception
} ?: throw BackgroundPlaybackVideoIdParentFingerprint.exception
/**
* Inject call for video id
*/
VideoIdParentFingerprint.result?.let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetReference = getInstruction<ReferenceInstruction>(targetIndex).reference
val targetClass = (targetReference as FieldReference).type
videoIdMethod = context
.findClass(targetClass)!!
.mutableClass.methods.first { method ->
method.name == "handleVideoStageEvent"
}
}
} ?: throw VideoIdParentFingerprint.exception
videoIdMethod.apply {
for (index in implementation!!.instructions.size - 1 downTo 0) {
if (getInstruction(index).opcode != Opcode.INVOKE_INTERFACE) continue
val targetReference = getInstruction<ReferenceInstruction>(index).reference
if (!targetReference.toString().endsWith("Ljava/lang/String;")) continue
videoIdIndex = index + 1
videoIdRegister = getInstruction<OneRegisterInstruction>(videoIdIndex).registerA
break
}
offset++ // offset so setVideoId is called before any injected call
}
/**
* Set current video id

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object VideoIdFingerprint : MethodFingerprint(
object BackgroundPlaybackVideoIdFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf("L", "L", "L"),
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,

View File

@ -0,0 +1,12 @@
package app.revanced.patches.music.video.information.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
object BackgroundPlaybackVideoIdParentFingerprint : MethodFingerprint(
returnType = "V",
parameters = emptyList(),
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("currentWatchNextResponse")
)

View File

@ -3,10 +3,18 @@ package app.revanced.patches.music.video.information.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object VideoIdParentFingerprint : MethodFingerprint(
returnType = "V",
parameters = emptyList(),
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("currentWatchNextResponse")
opcodes = listOf(
Opcode.INVOKE_SUPER,
Opcode.IGET_OBJECT,
Opcode.CONST_4,
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT
),
customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/WatchFragment;") && methodDef.name == "onDestroyView" }
)