diff --git a/src/main/kotlin/app/revanced/patches/music/utils/returnyoutubedislike/ReturnYouTubeDislikeBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/returnyoutubedislike/ReturnYouTubeDislikeBytecodePatch.kt index af566af07..67862b843 100644 --- a/src/main/kotlin/app/revanced/patches/music/utils/returnyoutubedislike/ReturnYouTubeDislikeBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/returnyoutubedislike/ReturnYouTubeDislikeBytecodePatch.kt @@ -13,7 +13,7 @@ import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.Dislik import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.LikeFingerprint import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.RemoveLikeFingerprint import app.revanced.patches.music.utils.returnyoutubedislike.fingerprints.TextComponentFingerprint -import app.revanced.patches.music.video.information.VideoInformationPatch +import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -22,7 +22,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c @Patch( dependencies = [ SharedResourceIdPatch::class, - VideoInformationPatch::class + VideoIdPatch::class ] ) object ReturnYouTubeDislikeBytecodePatch : BytecodePatch( @@ -80,7 +80,7 @@ object ReturnYouTubeDislikeBytecodePatch : BytecodePatch( } } ?: throw TextComponentFingerprint.exception - VideoInformationPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") + VideoIdPatch.hookVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") } 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 fa6a29fa0..684796dd5 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 @@ -7,12 +7,12 @@ 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 import app.revanced.patches.music.utils.sponsorblock.bytecode.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.music.video.information.VideoInformationPatch +import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction3rc @@ -24,9 +24,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( dependencies = [ - PlayerResponsePatch::class, SharedResourceIdPatch::class, - VideoInformationPatch::class + VideoInformationPatch::class, + VideoIdPatch::class ] ) object SponsorBlockBytecodePatch : BytecodePatch( @@ -165,8 +165,7 @@ 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") + VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") + VideoIdPatch.hookVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") } } 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 072002968..58a4232a4 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,15 +12,12 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu import app.revanced.patches.music.utils.fingerprints.SeekBarConstructorFingerprint import app.revanced.patches.music.utils.integrations.Constants.VIDEO_PATH 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.VideoIdParentFingerprint import app.revanced.patches.music.video.information.fingerprints.VideoLengthFingerprint +import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.util.exception import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -29,57 +26,31 @@ 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 = [SharedResourceIdPatch::class]) +@Patch( + dependencies = [ + SharedResourceIdPatch::class, + VideoIdPatch::class + ] +) +@Suppress("MemberVisibilityCanBePrivate") object VideoInformationPatch : BytecodePatch( setOf( - BackgroundPlaybackVideoIdParentFingerprint, PlayerControllerSetTimeReferenceFingerprint, SeekBarConstructorFingerprint, - VideoEndFingerprint, - VideoIdParentFingerprint + VideoEndFingerprint ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$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;` - */ - internal fun injectCall( - methodDescriptor: String - ) { - videoIdMethod.addInstructions( - videoIdIndex + offset, // move-result-object offset - "invoke-static {v$videoIdRegister}, $methodDescriptor" - ) - } - private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) = addInstruction(insertIndex, "invoke-static { $register }, $descriptor") @@ -195,65 +166,11 @@ object VideoInformationPatch : BytecodePatch( videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime") - /** - * Inject call for background playback video id - */ - BackgroundPlaybackVideoIdParentFingerprint.result?.let { parentResult -> - BackgroundPlaybackVideoIdFingerprint.also { - it.resolve( - context, - parentResult.classDef - ) - }.result?.let { - it.mutableMethod.apply { - backgroundPlaybackMethod = this - backgroundPlaybackInsertIndex = it.scanResult.patternScanResult!!.endIndex - backgroundPlaybackVideoIdRegister = - getInstruction(backgroundPlaybackInsertIndex).registerA - backgroundPlaybackInsertIndex++ - } - } ?: 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 */ - injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") + val videoIdMethodDescriptor = "$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V" + VideoIdPatch.hookVideoId(videoIdMethodDescriptor) + VideoIdPatch.hookBackgroundPlayVideoId(videoIdMethodDescriptor) } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/video/quality/VideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/music/video/quality/VideoQualityPatch.kt index 6de932a43..68945ee12 100644 --- a/src/main/kotlin/app/revanced/patches/music/video/quality/VideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/video/quality/VideoQualityPatch.kt @@ -11,8 +11,8 @@ import app.revanced.patches.music.utils.integrations.Constants.VIDEO_PATH import app.revanced.patches.music.utils.overridequality.OverrideQualityHookPatch import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.SettingsPatch -import app.revanced.patches.music.video.information.VideoInformationPatch import app.revanced.patches.music.video.quality.fingerprints.UserQualityChangeFingerprint +import app.revanced.patches.music.video.videoid.VideoIdPatch import app.revanced.util.exception import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c @@ -22,7 +22,7 @@ import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c dependencies = [ OverrideQualityHookPatch::class, SettingsPatch::class, - VideoInformationPatch::class + VideoIdPatch::class ], compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] ) @@ -56,7 +56,7 @@ object VideoQualityPatch : BytecodePatch( } } ?: throw UserQualityChangeFingerprint.exception - VideoInformationPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + VideoIdPatch.hookVideoId("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") SettingsPatch.addMusicPreference( CategoryType.VIDEO, diff --git a/src/main/kotlin/app/revanced/patches/music/video/videoid/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/music/video/videoid/VideoIdPatch.kt new file mode 100644 index 000000000..7155ab6ca --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/video/videoid/VideoIdPatch.kt @@ -0,0 +1,97 @@ +package app.revanced.patches.music.video.videoid + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.music.video.videoid.fingerprints.PlayerResponseModelImplGeneralFingerprint +import app.revanced.patches.music.video.videoid.fingerprints.VideoIdParentFingerprint +import app.revanced.util.exception +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.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import java.io.Closeable + +object VideoIdPatch : BytecodePatch( + setOf( + PlayerResponseModelImplGeneralFingerprint, + VideoIdParentFingerprint + ) +), Closeable { + private var videoIdRegister = 0 + private var videoIdInsertIndex = 0 + private lateinit var videoIdMethod: MutableMethod + + private var backgroundPlaybackVideoIdRegister = 0 + private var backgroundPlaybackInsertIndex = 0 + private var backgroundPlaybackMethodName = "" + private lateinit var backgroundPlaybackMethod: MutableMethod + + override fun execute(context: BytecodeContext) { + + VideoIdParentFingerprint.result?.let { result -> + val targetIndex = result.scanResult.patternScanResult!!.endIndex + val targetReference = result.mutableMethod.getInstruction(targetIndex).reference + val targetClass = (targetReference as FieldReference).type + + context.findClass(targetClass)!! + .mutableClass.methods.first { method -> method.name == "handleVideoStageEvent" } + .apply { + videoIdMethod = this + videoIdInsertIndex = implementation!!.instructions.indexOfLast { instruction -> + val invokeReference = ((instruction as? ReferenceInstruction)?.reference) as? MethodReference + backgroundPlaybackMethodName = invokeReference?.name.toString() + + instruction.opcode == Opcode.INVOKE_INTERFACE + && invokeReference?.returnType == "Ljava/lang/String;" + } + 2 + + videoIdRegister = getInstruction(videoIdInsertIndex - 1).registerA + } + } ?: throw VideoIdParentFingerprint.exception + + PlayerResponseModelImplGeneralFingerprint.result + ?.mutableClass?.methods?.find { method -> method.name == backgroundPlaybackMethodName } + ?.apply { + backgroundPlaybackMethod = this + backgroundPlaybackInsertIndex = implementation!!.instructions.size - 1 + backgroundPlaybackVideoIdRegister = getInstruction(backgroundPlaybackInsertIndex).registerA + } ?: throw PlayerResponseModelImplGeneralFingerprint.exception + } + + override fun close() { + backgroundPlaybackMethod.apply { + val insertIndex = implementation!!.instructions.indexOfLast { instruction -> + instruction.opcode == Opcode.IGET_OBJECT + } + 1 + + if (insertIndex != backgroundPlaybackInsertIndex) { + addInstructionsWithLabels( + insertIndex, """ + if-eqz v$backgroundPlaybackVideoIdRegister, :ignore + """, ExternalLabel("ignore", getInstruction(backgroundPlaybackInsertIndex)) + ) + } + } + } + + fun hookVideoId( + methodDescriptor: String + ) = videoIdMethod.addInstruction( + videoIdInsertIndex++, + "invoke-static {v$videoIdRegister}, $methodDescriptor" + ) + + fun hookBackgroundPlayVideoId( + methodDescriptor: String + ) = backgroundPlaybackMethod.addInstruction( + backgroundPlaybackInsertIndex++, // move-result-object offset + "invoke-static {v$backgroundPlaybackVideoIdRegister}, $methodDescriptor" + ) +} + diff --git a/src/main/kotlin/app/revanced/patches/music/video/videoid/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/videoid/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt new file mode 100644 index 000000000..51922ca29 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/video/videoid/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.music.video.videoid.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.util.fingerprint.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object PlayerResponseModelImplGeneralFingerprint : LiteralValueFingerprint( + returnType = "Ljava/lang/String;", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = emptyList(), + opcodes = listOf( + Opcode.RETURN_OBJECT, + Opcode.CONST_4, + Opcode.RETURN_OBJECT + ), + literalSupplier = {55735497} +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/videoid/fingerprints/VideoIdParentFingerprint.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/video/videoid/fingerprints/VideoIdParentFingerprint.kt index 095133eb4..4c2de4ec4 100644 --- a/src/main/kotlin/app/revanced/patches/music/video/information/fingerprints/VideoIdParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/video/videoid/fingerprints/VideoIdParentFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.music.video.information.fingerprints +package app.revanced.patches.music.video.videoid.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint