diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt index 676283423..b1b8231b8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt @@ -15,12 +15,13 @@ import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility import app.revanced.patches.youtube.ad.video.fingerprints.LoadVideoAdsFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.playback.patch.FixPlaybackPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference @Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) +@DependsOn([IntegrationsPatch::class, SettingsPatch::class, FixPlaybackPatch::class]) @Name("video-ads") @Description("Removes ads in the video player.") @VideoAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt index 7838a58f2..eabafce90 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt @@ -7,40 +7,41 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.youtube.layout.autocaptions.fingerprints.StartVideoInformerFingerprint import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.* import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.mapping.patch.ResourceMappingResourcePatch +import app.revanced.patches.youtube.misc.playercontroller.patch.PlayerControllerPatch import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch -import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.iface.instruction.* import org.jf.dexlib2.iface.instruction.formats.Instruction35c import org.jf.dexlib2.iface.reference.FieldReference import org.jf.dexlib2.iface.reference.MethodReference import org.jf.dexlib2.iface.reference.StringReference -import org.jf.dexlib2.immutable.ImmutableMethod -import org.jf.dexlib2.immutable.ImmutableMethodParameter -import org.jf.dexlib2.util.MethodUtil @Patch @DependsOn( - dependencies = [PlayerControlsBytecodePatch::class, IntegrationsPatch::class, SponsorBlockResourcePatch::class, VideoIdPatch::class] + dependencies = [ + PlayerControllerPatch::class, // updates video length and adds method to seek in video + PlayerControlsBytecodePatch::class, + IntegrationsPatch::class, + SponsorBlockResourcePatch::class, + VideoIdPatch::class + ] ) @Name("sponsorblock") @Description("Integrate SponsorBlock.") @@ -53,7 +54,6 @@ class SponsorBlockBytecodePatch : BytecodePatch( VideoTimeFingerprint, NextGenWatchLayoutFingerprint, AppendTimeFingerprint, - PlayerInitFingerprint, PlayerOverlaysLayoutInitFingerprint, ShortsPlayerConstructorFingerprint, StartVideoInformerFingerprint @@ -160,23 +160,6 @@ class SponsorBlockBytecodePatch : BytecodePatch( "invoke-static {v$canvasInstance, v$centerY}, Lapp/revanced/integrations/sponsorblock/PlayerController;->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V" ) - /* - Set video length - */ - VideoLengthFingerprint.resolve(context, seekbarSignatureResult.classDef) - val videoLengthMethodResult = VideoLengthFingerprint.result!! - val videoLengthMethod = videoLengthMethodResult.mutableMethod - val videoLengthMethodInstructions = videoLengthMethod.implementation!!.instructions - - val videoLengthRegister = - (videoLengthMethodInstructions[videoLengthMethodResult.scanResult.patternScanResult!!.endIndex - 2] as OneRegisterInstruction).registerA - val dummyRegisterForLong = - videoLengthRegister + 1 // this is required for long values since they are 64 bit wide - videoLengthMethod.addInstruction( - videoLengthMethodResult.scanResult.patternScanResult!!.endIndex, - "invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, Lapp/revanced/integrations/sponsorblock/PlayerController;->setVideoLength(J)V" - ) - /* Voting & Shield button */ @@ -249,12 +232,7 @@ class SponsorBlockBytecodePatch : BytecodePatch( ) // initialize the player controller - val initFingerprintResult = PlayerInitFingerprint.result!! - val initInstanceRegister = 0 - initFingerprintResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }.addInstruction( - 4, // after super class invoke - "invoke-static {v$initInstanceRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->onCreate(Ljava/lang/Object;)V" - ) + PlayerControllerPatch.onCreateHook("Lapp/revanced/integrations/sponsorblock/PlayerController;", "initialize") // initialize the sponsorblock view PlayerOverlaysLayoutInitFingerprint.result!!.mutableMethod.addInstruction( @@ -262,39 +240,6 @@ class SponsorBlockBytecodePatch : BytecodePatch( "invoke-static {p0}, Lapp/revanced/integrations/sponsorblock/player/ui/SponsorBlockView;->initialize(Ljava/lang/Object;)V" ) - // lastly create hooks for the player controller - - // get original seek method - SeekFingerprint.resolve(context, initFingerprintResult.classDef) - val seekFingerprintResultMethod = SeekFingerprint.result!!.method - // get enum type for the seek helper method - val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString() - - // create helper method - val seekHelperMethod = ImmutableMethod( - seekFingerprintResultMethod.definingClass, - "seekHelper", - listOf(ImmutableMethodParameter("J", null, "time")), - "Z", - AccessFlags.PUBLIC or AccessFlags.FINAL, - null, null, - MutableMethodImplementation(4) - ).toMutable() - - // insert helper method instructions - seekHelperMethod.addInstructions( - 0, - """ - sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType - invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z - move-result p1 - return p1 - """ - ) - - // add the helper method to the original class - initFingerprintResult.mutableClass.methods.add(seekHelperMethod) - // get rectangle field name RectangleFieldInvalidatorFingerprint.resolve(context, seekbarSignatureResult.classDef) val rectangleFieldInvalidatorInstructions = @@ -302,35 +247,31 @@ class SponsorBlockBytecodePatch : BytecodePatch( val rectangleFieldName = ((rectangleFieldInvalidatorInstructions.elementAt(rectangleFieldInvalidatorInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name - // get the player controller class from the integrations - val playerControllerMethods = - context.proxy(context.classes.first { it.type.endsWith("PlayerController;") }).mutableClass.methods - - // get the method which contain the "replaceMe" strings - val replaceMeMethods = - playerControllerMethods.filter { it.name == "onCreate" || it.name == "setSponsorBarRect" } - - fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { - val register = (instruction as OneRegisterInstruction).registerA - this.replaceInstruction( - index, "const-string v$register, \"$with\"" - ) - } - // replace the "replaceMeWith*" strings - for (method in replaceMeMethods) { - for ((index, it) in method.implementation!!.instructions.withIndex()) { - if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue - - when (((it as ReferenceInstruction).reference as StringReference).string) { - "replaceMeWithsetSponsorBarRect" -> - method.replaceStringInstruction(index, it, rectangleFieldName) - - "replaceMeWithsetMillisecondMethod" -> - method.replaceStringInstruction(index, it, "seekHelper") + context + .proxy(context.classes.first { it.type.endsWith("PlayerController;") }) + .mutableClass + .methods + .find { it.name == "setSponsorBarRect" } + ?.let { method -> + fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { + val register = (instruction as OneRegisterInstruction).registerA + this.replaceInstruction( + index, "const-string v$register, \"$with\"" + ) } - } - } + for ((index, it) in method.implementation!!.instructions.withIndex()) { + if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue + + when (((it as ReferenceInstruction).reference as StringReference).string) { + "replaceMeWithsetSponsorBarRect" -> + method.replaceStringInstruction(index, it, rectangleFieldName) + + "replaceMeWithsetMillisecondMethod" -> + method.replaceStringInstruction(index, it, "seekHelper") + } + } + } ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings") val startVideoInformerMethod = StartVideoInformerFingerprint.result!!.mutableMethod startVideoInformerMethod.addInstructions( diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playback/annotations/FixPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playback/annotations/FixPlaybackCompatibility.kt new file mode 100644 index 000000000..8b2d1e74c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playback/annotations/FixPlaybackCompatibility.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.misc.playback.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.41.37") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class FixPlaybackCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playback/patch/FixPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playback/patch/FixPlaybackPatch.kt new file mode 100644 index 000000000..1ffb2098f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playback/patch/FixPlaybackPatch.kt @@ -0,0 +1,52 @@ +package app.revanced.patches.youtube.misc.playback.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.playback.annotations.FixPlaybackCompatibility +import app.revanced.patches.youtube.misc.playercontroller.patch.PlayerControllerPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference +import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch + +@DependsOn([ + IntegrationsPatch::class, + PlayerControllerPatch::class, // updates video length and adds method to seek in video, necessary for this patch + SettingsPatch::class, + VideoIdPatch::class +]) +@Name("fix-playback") +@Description("Fixes the issue with videos not playing when video ads are removed.") +@FixPlaybackCompatibility +@Version("0.0.1") +class FixPlaybackPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_fix_playback", + StringResource("revanced_fix_playback_title", "Fix video playback issues"), + false, + StringResource( + "revanced_fix_playback_summary_on", + "The fix is enabled" + ), + StringResource( + "revanced_fix_playback_summary_off", + "The fix is disabled" + ) + ) + ) + + // If a new video loads, fix the playback issue + VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/FixPlaybackPatch;->newVideoLoaded(Ljava/lang/String;)V") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/annotation/PlayerControllerCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/annotation/PlayerControllerCompatibility.kt new file mode 100644 index 000000000..af62a0bec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/annotation/PlayerControllerCompatibility.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.misc.playercontroller.annotation + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.41.37") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class PlayerControllerCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/CreateVideoPlayerSeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/CreateVideoPlayerSeekbarFingerprint.kt new file mode 100644 index 000000000..f0fa35acf --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/CreateVideoPlayerSeekbarFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.misc.playercontroller.fingerprint + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility + +@Name("create-video-player-seekbar-fingerprint") +@SponsorBlockCompatibility +@Version("0.0.1") +object CreateVideoPlayerSeekbarFingerprint : MethodFingerprint( + "V", + strings = listOf("timed_markers_width") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/PlayerInitFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/PlayerInitFingerprint.kt index 4ddc5c722..81f5a61fc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerInitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/PlayerInitFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints +package app.revanced.patches.youtube.misc.playercontroller.fingerprint import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/SeekFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/SeekFingerprint.kt index 6513e4608..00fa1c874 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/SeekFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/SeekFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints +package app.revanced.patches.youtube.misc.playercontroller.fingerprint import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/VideoLengthFingerprint.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/VideoLengthFingerprint.kt index 5bf3b461c..223713044 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/VideoLengthFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/fingerprint/VideoLengthFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints +package app.revanced.patches.youtube.misc.playercontroller.fingerprint import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/patch/PlayerControllerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/patch/PlayerControllerPatch.kt new file mode 100644 index 000000000..efa8d4602 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontroller/patch/PlayerControllerPatch.kt @@ -0,0 +1,116 @@ +package app.revanced.patches.youtube.misc.playercontroller.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.playercontroller.annotation.PlayerControllerCompatibility +import app.revanced.patches.youtube.misc.playercontroller.fingerprint.CreateVideoPlayerSeekbarFingerprint +import app.revanced.patches.youtube.misc.playercontroller.fingerprint.PlayerInitFingerprint +import app.revanced.patches.youtube.misc.playercontroller.fingerprint.SeekFingerprint +import app.revanced.patches.youtube.misc.playercontroller.fingerprint.VideoLengthFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.builder.MutableMethodImplementation +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodParameter +import org.jf.dexlib2.util.MethodUtil + +@Name("player-controller-hook") +@Description("Hooks the player controller") +@PlayerControllerCompatibility +@Version("0.0.1") +@DependsOn([IntegrationsPatch::class]) +class PlayerControllerPatch : BytecodePatch( + listOf( + PlayerInitFingerprint, + CreateVideoPlayerSeekbarFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + with(PlayerInitFingerprint.result!!) { + playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) } + + // hook the player controller for use through integrations + onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "playerController_onCreateHook") + + // seek method + val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method + + // create helper method + val seekHelperMethod = ImmutableMethod( + seekFingerprintResultMethod.definingClass, + "seekTo", + listOf(ImmutableMethodParameter("J", null, "time")), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + null, null, + MutableMethodImplementation(4) + ).toMutable() + + // get enum type for the seek helper method + val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString() + + // insert helper method instructions + seekHelperMethod.addInstructions( + 0, + """ + sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType + invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z + move-result p1 + return p1 + """ + ) + + // add the seekTo method to the class for the integrations to call + mutableClass.methods.add(seekHelperMethod) + } + + with(CreateVideoPlayerSeekbarFingerprint.result!!) { + val videoLengthMethodResult = VideoLengthFingerprint.also { it.resolve(context, classDef) }.result!! + + with(videoLengthMethodResult.mutableMethod) { + val videoLengthRegisterIndex = videoLengthMethodResult.scanResult.patternScanResult!!.endIndex - 2 + val videoLengthRegister = (instruction(videoLengthRegisterIndex) as OneRegisterInstruction).registerA + val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide + + addInstruction( + videoLengthMethodResult.scanResult.patternScanResult!!.endIndex, + "invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, $INTEGRATIONS_CLASS_DESCRIPTOR->setCurrentVideoLength(J)V" + ) + } + } + + return PatchResultSuccess() + } + + companion object { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/PlayerControllerPatch;" + private const val INSERT_INDEX = 4 + + private lateinit var playerInitMethod: MutableMethod + + /** + * Hook the player controller. + * + * @param targetMethodClass The descriptor for the static method to invoke when the player controller is created. + */ + internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) = + playerInitMethod.addInstruction( + INSERT_INDEX, + "invoke-static { v0 }, $targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt index 5b03992ee..dfeb16992 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/patch/VideoIdPatch.kt @@ -17,7 +17,7 @@ import app.revanced.patches.youtube.misc.videoid.fingerprint.VideoIdFingerprint import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Name("video-id-hook") -@Description("Hook to detect when the video id changes") +@Description("Hooks to detect when the video id changes") @VideoIdCompatibility @Version("0.0.1") @DependsOn([IntegrationsPatch::class])