diff --git a/src/main/kotlin/app/revanced/patches/music/player/replace/ReplaceCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/music/player/replace/ReplaceCastButtonPatch.kt index 796a76d3d..14144ecd1 100644 --- a/src/main/kotlin/app/revanced/patches/music/player/replace/ReplaceCastButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/player/replace/ReplaceCastButtonPatch.kt @@ -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( diff --git a/src/main/kotlin/app/revanced/patches/music/utils/playerresponse/PlayerResponsePatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/playerresponse/PlayerResponsePatch.kt new file mode 100644 index 000000000..2257c52a8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/utils/playerresponse/PlayerResponsePatch.kt @@ -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 + + } + +} + diff --git a/src/main/kotlin/app/revanced/patches/music/player/replace/fingerprints/PlaybackStartDescriptorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/utils/playerresponse/fingerprints/PlaybackStartDescriptorFingerprint.kt similarity index 91% rename from src/main/kotlin/app/revanced/patches/music/player/replace/fingerprints/PlaybackStartDescriptorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/utils/playerresponse/fingerprints/PlaybackStartDescriptorFingerprint.kt index efc0c5c9b..e312b9e7b 100644 --- a/src/main/kotlin/app/revanced/patches/music/player/replace/fingerprints/PlaybackStartDescriptorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/playerresponse/fingerprints/PlaybackStartDescriptorFingerprint.kt @@ -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 diff --git a/src/main/kotlin/app/revanced/patches/music/utils/sponsorblock/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/sponsorblock/SponsorBlockBytecodePatch.kt index 08ae75d90..43024acd8 100644 --- a/src/main/kotlin/app/revanced/patches/music/utils/sponsorblock/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/sponsorblock/SponsorBlockBytecodePatch.kt @@ -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 } diff --git a/src/main/kotlin/app/revanced/patches/music/utils/videotype/VideoTypeHookPatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/videotype/VideoTypeHookPatch.kt index ef6811610..8bf01a4ab 100644 --- a/src/main/kotlin/app/revanced/patches/music/utils/videotype/VideoTypeHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/videotype/VideoTypeHookPatch.kt @@ -26,7 +26,8 @@ object VideoTypeHookPatch : BytecodePatch( it.mutableMethod.apply { val insertIndex = it.scanResult.patternScanResult!!.startIndex + 3 val referenceIndex = insertIndex + 1 - val referenceInstruction = getInstruction(referenceIndex).reference + val referenceInstruction = + getInstruction(referenceIndex).reference addInstructionsWithLabels( insertIndex, """ diff --git a/src/main/kotlin/app/revanced/patches/music/video/information/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/music/video/information/VideoInformationPatch.kt index ede57bca9..a9e97a317 100644 --- a/src/main/kotlin/app/revanced/patches/music/video/information/VideoInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/video/information/VideoInformationPatch.kt @@ -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(videoIdIndex).registerA + backgroundPlaybackMethod = this + backgroundPlaybackInsertIndex = it.scanResult.patternScanResult!!.endIndex + backgroundPlaybackVideoIdRegister = + getInstruction(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(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(index).reference + + if (!targetReference.toString().endsWith("Ljava/lang/String;")) continue + + videoIdIndex = index + 1 + videoIdRegister = getInstruction(videoIdIndex).registerA + + break + } + offset++ // offset so setVideoId is called before any injected call + } + /** * Set current video id diff --git a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/BackgroundPlaybackVideoIdFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/BackgroundPlaybackVideoIdFingerprint.kt index de7194c8b..eab38dbad 100644 --- a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/BackgroundPlaybackVideoIdFingerprint.kt @@ -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, diff --git a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/BackgroundPlaybackVideoIdParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/BackgroundPlaybackVideoIdParentFingerprint.kt new file mode 100644 index 000000000..578441bb1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/BackgroundPlaybackVideoIdParentFingerprint.kt @@ -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") +) diff --git a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt index ed7487eb3..095133eb4 100644 --- a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt @@ -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" } )