From 7ba43b6f4c63f59d24814270398f3f8eae40aac4 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 6 Apr 2024 01:36:03 +0900 Subject: [PATCH] refactor(YouTube/Video information): include playback speed --- .../oldqualitylayout/OldQualityLayoutPatch.kt | 6 +- .../general/autocaptions/AutoCaptionsPatch.kt | 4 +- .../alwaysrepeat/AlwaysRepeatPatch.kt | 7 +- .../general/OverlayButtonsPatch.kt | 8 +- .../append/AppendTimeStampInformationPatch.kt | 6 +- ...lityChangedFromRecyclerViewFingerprint.kt} | 2 +- ...erprint.kt => QualitySetterFingerprint.kt} | 2 +- .../parameter/SpoofPlayerParameterPatch.kt | 12 +- .../overridespeed/OverrideSpeedHookPatch.kt | 150 --------- .../PlaybackSpeedChangedFingerprint.kt | 16 - .../PlaybackSpeedParentFingerprint.kt | 18 - .../playerresponse/PlayerResponsePatch.kt | 102 ------ .../general/ReturnYouTubeDislikePatch.kt | 18 +- .../sponsorblock/SponsorBlockBytecodePatch.kt | 16 +- .../youtube/utils/videocpn/VideoCpnPatch.kt | 33 -- .../utils/videoid/general/VideoIdPatch.kt | 247 -------------- .../VideoIdWithoutShortsPatch.kt | 52 --- .../customspeed/CustomPlaybackSpeedPatch.kt | 6 +- .../information/VideoInformationPatch.kt | 313 ++++++++++++++++++ .../OnPlaybackSpeedItemClickFingerprint.kt | 20 ++ .../PlaybackSpeedClassFingerprint.kt} | 4 +- ...erControllerSetTimeReferenceFingerprint.kt | 2 +- .../VideoInformationPatchFingerprint.kt} | 8 +- .../fingerprints}/VideoLengthFingerprint.kt | 2 +- .../PlayerResponseMethodHookPatch.kt | 106 ++++++ .../PlayerParameterBuilderFingerprint.kt | 4 +- .../video/quality/VideoQualityPatch.kt | 37 +-- .../youtube/video/speed/PlaybackSpeedPatch.kt | 56 ++-- ...peedChangedFromRecyclerViewFingerprint.kt} | 2 +- .../youtube/video/videoid/VideoIdPatch.kt | 136 ++++++++ .../fingerprints}/VideoIdFingerprint.kt | 2 +- .../VideoIdFingerprintBackgroundPlay.kt} | 7 +- .../fingerprints}/VideoIdParentFingerprint.kt | 2 +- 33 files changed, 685 insertions(+), 721 deletions(-) rename src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/{NewVideoQualityChangedFingerprint.kt => QualityChangedFromRecyclerViewFingerprint.kt} (92%) rename src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/{VideoQualitySetterFingerprint.kt => QualitySetterFingerprint.kt} (85%) delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/OverrideSpeedHookPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedChangedFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedParentFingerprint.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/PlayerResponsePatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/videocpn/VideoCpnPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/VideoIdPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/VideoIdWithoutShortsPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt rename src/main/kotlin/app/revanced/patches/youtube/{utils/overridespeed/fingerprints/SpeedClassFingerprint.kt => video/information/fingerprints/PlaybackSpeedClassFingerprint.kt} (75%) rename src/main/kotlin/app/revanced/patches/youtube/{utils/videoid/general/fingerprint => video/information/fingerprints}/PlayerControllerSetTimeReferenceFingerprint.kt (83%) rename src/main/kotlin/app/revanced/patches/youtube/{utils/overridespeed/fingerprints/PlaybackSpeedPatchFingerprint.kt => video/information/fingerprints/VideoInformationPatchFingerprint.kt} (59%) rename src/main/kotlin/app/revanced/patches/youtube/{utils/videoid/general/fingerprint => video/information/fingerprints}/VideoLengthFingerprint.kt (88%) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt rename src/main/kotlin/app/revanced/patches/youtube/{utils/playerresponse/fingerprints => video/playerresponse/fingerprint}/PlayerParameterBuilderFingerprint.kt (85%) rename src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/{NewPlaybackSpeedChangedFingerprint.kt => PlaybackSpeedChangedFromRecyclerViewFingerprint.kt} (88%) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt rename src/main/kotlin/app/revanced/patches/youtube/{utils/videoid/general/fingerprint => video/videoid/fingerprints}/VideoIdFingerprint.kt (88%) rename src/main/kotlin/app/revanced/patches/youtube/{utils/videoid/withoutshorts/fingerprint/VideoIdWithoutShortsFingerprint.kt => video/videoid/fingerprints/VideoIdFingerprintBackgroundPlay.kt} (79%) rename src/main/kotlin/app/revanced/patches/youtube/{utils/videoid/general/fingerprint => video/videoid/fingerprints}/VideoIdParentFingerprint.kt (79%) diff --git a/src/main/kotlin/app/revanced/patches/youtube/flyoutpanel/oldqualitylayout/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/flyoutpanel/oldqualitylayout/OldQualityLayoutPatch.kt index 99c4da39a..69cf45c8c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/flyoutpanel/oldqualitylayout/OldQualityLayoutPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/flyoutpanel/oldqualitylayout/OldQualityLayoutPatch.kt @@ -8,7 +8,7 @@ import app.revanced.patcher.patch.PatchException import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.youtube.utils.fingerprints.QualityMenuViewInflateFingerprint -import app.revanced.patches.youtube.utils.fingerprints.VideoQualitySetterFingerprint +import app.revanced.patches.youtube.utils.fingerprints.QualitySetterFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.integrations.Constants.FLYOUT_PANEL_CLASS_DESCRIPTOR @@ -38,7 +38,7 @@ object OldQualityLayoutPatch : BaseBytecodePatch( compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( QualityMenuViewInflateFingerprint, - VideoQualitySetterFingerprint + QualitySetterFingerprint ) ) { private const val FILTER_CLASS_DESCRIPTOR = @@ -49,7 +49,7 @@ object OldQualityLayoutPatch : BaseBytecodePatch( /** * Non-litho view, used in old clients and Shorts. */ - val videoQualityClass = VideoQualitySetterFingerprint.resultOrThrow().mutableMethod.definingClass + val videoQualityClass = QualitySetterFingerprint.resultOrThrow().mutableMethod.definingClass QualityMenuViewInflateFingerprint.resultOrThrow().let { it.mutableMethod.apply { diff --git a/src/main/kotlin/app/revanced/patches/youtube/general/autocaptions/AutoCaptionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/general/autocaptions/AutoCaptionsPatch.kt index e6445a5b1..0e3c55475 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/general/autocaptions/AutoCaptionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/general/autocaptions/AutoCaptionsPatch.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patches.youtube.utils.integrations.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.utils.videoid.general.VideoIdPatch +import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.util.patch.BaseBytecodePatch @Suppress("unused") @@ -20,7 +20,7 @@ object AutoCaptionsPatch : BaseBytecodePatch( ) { override fun execute(context: BytecodeContext) { - VideoIdPatch.injectCall("$GENERAL_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + VideoIdPatch.hookBackgroundPlayVideoId("$GENERAL_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") /** * Add settings diff --git a/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/alwaysrepeat/AlwaysRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/alwaysrepeat/AlwaysRepeatPatch.kt index 79a988284..4c478d169 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/alwaysrepeat/AlwaysRepeatPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/alwaysrepeat/AlwaysRepeatPatch.kt @@ -6,9 +6,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patches.youtube.overlaybutton.alwaysrepeat.fingerprints.AutoNavInformerFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH +import app.revanced.util.getTargetIndexReversed import app.revanced.util.getWalkerMethod import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction object AlwaysRepeatPatch : BytecodePatch( setOf(AutoNavInformerFingerprint) @@ -18,8 +21,8 @@ object AlwaysRepeatPatch : BytecodePatch( AutoNavInformerFingerprint.resultOrThrow().let { val walkerMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex) walkerMethod.apply { - val index = implementation!!.instructions.size - 2 - val register = getInstruction(index).registerA + val index = getTargetIndexReversed(Opcode.IGET_BOOLEAN) + val register = getInstruction(index).registerA addInstructions( index + 1, """ diff --git a/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/general/OverlayButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/general/OverlayButtonsPatch.kt index 8d0f30b93..295c0a24d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/general/OverlayButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/overlaybutton/general/OverlayButtonsPatch.kt @@ -9,11 +9,9 @@ import app.revanced.patches.youtube.overlaybutton.fullscreen.FullscreenButtonPat import app.revanced.patches.youtube.utils.fix.fullscreen.FullscreenButtonViewStubPatch import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.OVERLAY_BUTTONS_PATH -import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch import app.revanced.patches.youtube.utils.playercontrols.PlayerControlsPatch -import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch -import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch +import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.util.ResourceGroup import app.revanced.util.copyResources import app.revanced.util.copyXmlNode @@ -31,11 +29,9 @@ object OverlayButtonsPatch : BaseResourcePatch( DownloadButtonHookPatch::class, FullscreenButtonPatch::class, FullscreenButtonViewStubPatch::class, - OverrideSpeedHookPatch::class, PlayerControlsPatch::class, SettingsPatch::class, - SharedResourceIdPatch::class, - VideoIdPatch::class + VideoInformationPatch::class ), compatiblePackages = COMPATIBLE_PACKAGE ) { diff --git a/src/main/kotlin/app/revanced/patches/youtube/seekbar/append/AppendTimeStampInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/seekbar/append/AppendTimeStampInformationPatch.kt index 9729098fa..29650ae64 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/seekbar/append/AppendTimeStampInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/seekbar/append/AppendTimeStampInformationPatch.kt @@ -7,9 +7,9 @@ import app.revanced.patches.youtube.utils.fingerprints.TotalTimeFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.SEEKBAR_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch -import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch +import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.util.getTargetIndexWithMethodReferenceName import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow @@ -22,9 +22,9 @@ object AppendTimeStampInformationPatch : BaseBytecodePatch( description = "Adds an option to add the current video quality or playback speed in brackets next to the current time.", dependencies = setOf( OverrideQualityHookPatch::class, - OverrideSpeedHookPatch::class, SettingsPatch::class, - SharedResourceIdPatch::class + SharedResourceIdPatch::class, + VideoInformationPatch::class ), compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf(TotalTimeFingerprint) diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/NewVideoQualityChangedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/QualityChangedFromRecyclerViewFingerprint.kt similarity index 92% rename from src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/NewVideoQualityChangedFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/QualityChangedFromRecyclerViewFingerprint.kt index 28d8cb7ff..76cdc4d88 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/NewVideoQualityChangedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/QualityChangedFromRecyclerViewFingerprint.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 -internal object NewVideoQualityChangedFingerprint : MethodFingerprint( +internal object QualityChangedFromRecyclerViewFingerprint : MethodFingerprint( returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/VideoQualitySetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/QualitySetterFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/VideoQualitySetterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/QualitySetterFingerprint.kt index 605f5f78f..53689d9f0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/VideoQualitySetterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fingerprints/QualitySetterFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal object VideoQualitySetterFingerprint : MethodFingerprint( +internal object QualitySetterFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/SpoofPlayerParameterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/SpoofPlayerParameterPatch.kt index b2a3df4e9..f1c9903ff 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/SpoofPlayerParameterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/parameter/SpoofPlayerParameterPatch.kt @@ -16,10 +16,10 @@ import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardT import app.revanced.patches.youtube.utils.fix.parameter.fingerprints.StoryboardThumbnailParentFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH -import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch -import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch +import app.revanced.patches.youtube.video.information.VideoInformationPatch +import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -30,9 +30,9 @@ object SpoofPlayerParameterPatch : BaseBytecodePatch( description = "Adds options to spoof player parameters to prevent playback issues.", dependencies = setOf( PlayerTypeHookPatch::class, - PlayerResponsePatch::class, - VideoIdPatch::class, - SettingsPatch::class + PlayerResponseMethodHookPatch::class, + SettingsPatch::class, + VideoInformationPatch::class, ), compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( @@ -52,7 +52,7 @@ object SpoofPlayerParameterPatch : BaseBytecodePatch( override fun execute(context: BytecodeContext) { // Hook the player parameters. - PlayerResponsePatch += PlayerResponsePatch.Hook.PlayerParameter( + PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.PlayerParameter( "$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;" ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/OverrideSpeedHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/OverrideSpeedHookPatch.kt deleted file mode 100644 index 926364caa..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/OverrideSpeedHookPatch.kt +++ /dev/null @@ -1,150 +0,0 @@ -package app.revanced.patches.youtube.utils.overridespeed - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -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.MethodFingerprintResult -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patcher.util.smali.toInstructions -import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH -import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH -import app.revanced.patches.youtube.utils.overridespeed.fingerprints.PlaybackSpeedChangedFingerprint -import app.revanced.patches.youtube.utils.overridespeed.fingerprints.PlaybackSpeedParentFingerprint -import app.revanced.patches.youtube.utils.overridespeed.fingerprints.PlaybackSpeedPatchFingerprint -import app.revanced.patches.youtube.utils.overridespeed.fingerprints.SpeedClassFingerprint -import app.revanced.util.getWalkerMethod -import app.revanced.util.resultOrThrow -import com.android.tools.smali.dexlib2.AccessFlags -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.immutable.ImmutableField -import com.android.tools.smali.dexlib2.immutable.ImmutableMethod -import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation -import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter - -object OverrideSpeedHookPatch : BytecodePatch( - setOf( - PlaybackSpeedPatchFingerprint, - PlaybackSpeedParentFingerprint, - SpeedClassFingerprint - ) -) { - private const val INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR = - "$VIDEO_PATH/PlaybackSpeedPatch;" - - private const val INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR = - "$INTEGRATIONS_PATH/utils/VideoUtils;" - - lateinit var playbackSpeedChangedResult: MethodFingerprintResult - - private lateinit var objectClass: String - override fun execute(context: BytecodeContext) { - - PlaybackSpeedParentFingerprint.resultOrThrow().let { parentResult -> - val parentClassDef = parentResult.classDef - - PlaybackSpeedChangedFingerprint.also { - it.resolve( - context, - parentClassDef - ) - }.resultOrThrow().let { - it.mutableMethod.apply { - playbackSpeedChangedResult = it - val startIndex = it.scanResult.patternScanResult!!.startIndex - val endIndex = it.scanResult.patternScanResult!!.endIndex - - val reference1 = getInstruction(startIndex).reference - val reference2 = getInstruction(endIndex - 1).reference - val reference3 = getInstruction(endIndex).reference - val fieldReference = reference2 as FieldReference - - val parentMutableClass = parentResult.mutableClass - - parentMutableClass.methods.add( - ImmutableMethod( - parentMutableClass.type, - "overrideSpeed", - listOf(ImmutableMethodParameter("F", annotations, null)), - "V", - AccessFlags.PUBLIC or AccessFlags.PUBLIC, - annotations, - null, - ImmutableMethodImplementation( - 4, """ - const/4 v0, 0x0 - cmpg-float v0, v3, v0 - if-lez v0, :cond_0 - iget-object v0, v2, $reference1 - check-cast v0, ${fieldReference.definingClass} - iget-object v1, v0, $reference2 - invoke-virtual {v1, v3}, $reference3 - :cond_0 - return-void - """.toInstructions(), null, null - ) - ).toMutable() - ) - - val walkerMethod = getWalkerMethod(context, endIndex) - - walkerMethod.apply { - addInstruction( - this.implementation!!.instructions.size - 1, - "sput p1, $INTEGRATIONS_VIDEO_UTILS_CLASS_DESCRIPTOR->currentSpeed:F" - ) - } - } - - } - } - - - SpeedClassFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - val index = it.scanResult.patternScanResult!!.endIndex - val register = getInstruction(index).registerA - objectClass = this.returnType - replaceInstruction( - index, - "sput-object v$register, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->speedClass:$objectClass" - ) - addInstruction( - index + 1, - "return-object v$register" - ) - } - } - - PlaybackSpeedPatchFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - it.mutableClass.staticFields.add( - ImmutableField( - definingClass, - "speedClass", - objectClass, - AccessFlags.PUBLIC or AccessFlags.STATIC, - null, - annotations, - null - ).toMutable() - ) - - addInstructions( - 0, """ - sget-object v0, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->speedClass:$objectClass - invoke-virtual {v0, p0}, $objectClass->overrideSpeed(F)V - """ - ) - } - - } - - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedChangedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedChangedFingerprint.kt deleted file mode 100644 index abbdf2055..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedChangedFingerprint.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.youtube.utils.overridespeed.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.Opcode - -internal object PlaybackSpeedChangedFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.IF_EQZ, - Opcode.IF_EQZ, - Opcode.IGET, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL - ), - customFingerprint = { methodDef, _ -> methodDef.name == "onItemClick" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedParentFingerprint.kt deleted file mode 100644 index 2f76e0755..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedParentFingerprint.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.youtube.utils.overridespeed.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 - -internal object PlaybackSpeedParentFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, - parameters = listOf("L", "L", "[L", "I"), - opcodes = listOf( - Opcode.ARRAY_LENGTH, - Opcode.IF_GE, - Opcode.AGET_OBJECT, - Opcode.NEW_INSTANCE - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/PlayerResponsePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/PlayerResponsePatch.kt deleted file mode 100644 index ffed9f4e9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/PlayerResponsePatch.kt +++ /dev/null @@ -1,102 +0,0 @@ -package app.revanced.patches.youtube.utils.playerresponse - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -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.youtube.utils.playerresponse.fingerprints.PlayerParameterBuilderFingerprint -import app.revanced.util.resultOrThrow -import java.io.Closeable - -object PlayerResponsePatch : BytecodePatch( - setOf(PlayerParameterBuilderFingerprint) -), Closeable, MutableSet by mutableSetOf() { - private var VIDEO_ID_PARAMETER = 1 - private var PLAYER_PARAMETER = 3 - private var IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER = 11 - private var freeRegister = 0 - private var shouldApplyNewMethod = false - - private lateinit var playerResponseMethod: MutableMethod - - override fun execute(context: BytecodeContext) { - playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod - - playerResponseMethod.apply { - freeRegister = implementation!!.registerCount - parameters.size - 2 - shouldApplyNewMethod = freeRegister > 2 - if (shouldApplyNewMethod) { - IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER = freeRegister - PLAYER_PARAMETER = freeRegister - 1 - VIDEO_ID_PARAMETER = freeRegister - 2 - } - } - } - - override fun close() { - fun hookVideoId(hook: Hook) { - playerResponseMethod.apply { - val instruction = - if (shouldApplyNewMethod) - "invoke-static {v$VIDEO_ID_PARAMETER, v$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook" - else - "invoke-static {p$VIDEO_ID_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook" - addInstruction( - 0, - instruction - ) - } - } - - fun hookPlayerParameter(hook: Hook) { - playerResponseMethod.apply { - val instruction = - if (shouldApplyNewMethod) - """ - invoke-static {v$VIDEO_ID_PARAMETER, v$PLAYER_PARAMETER, v$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook - move-result-object p3 - """ - else - """ - invoke-static {p$VIDEO_ID_PARAMETER, p$PLAYER_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook - move-result-object p$PLAYER_PARAMETER - """ - addInstructions( - 0, - instruction - ) - } - } - - // Reverse the order in order to preserve insertion order of the hooks. - val beforeVideoIdHooks = filterIsInstance().asReversed() - val videoIdHooks = filterIsInstance().asReversed() - val afterVideoIdHooks = filterIsInstance().asReversed() - - // Add the hooks in this specific order as they insert instructions at the beginning of the method. - afterVideoIdHooks.forEach(::hookPlayerParameter) - videoIdHooks.forEach(::hookVideoId) - beforeVideoIdHooks.forEach(::hookPlayerParameter) - - if (shouldApplyNewMethod) { - playerResponseMethod.addInstructions( - 0, """ - move-object v$VIDEO_ID_PARAMETER, p1 - move-object v$PLAYER_PARAMETER, p3 - move/from16 v$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER, p11 - """ - ) - } - } - - internal abstract class Hook(private val methodDescriptor: String) { - internal class VideoId(methodDescriptor: String) : Hook(methodDescriptor) - - internal class PlayerParameter(methodDescriptor: String) : Hook(methodDescriptor) - internal class PlayerBeforeVideoId(methodDescriptor: String) : Hook(methodDescriptor) - - override fun toString() = methodDescriptor - } -} - diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/general/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/general/ReturnYouTubeDislikePatch.kt index c84fa61d2..f134e4796 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/general/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/general/ReturnYouTubeDislikePatch.kt @@ -8,7 +8,6 @@ import app.revanced.patches.shared.litho.LithoFilterPatch import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH -import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.DislikeFingerprint import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.LikeFingerprint import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.RemoveLikeFingerprint @@ -17,7 +16,7 @@ import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerpri import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.ReturnYouTubeDislikeRollingNumberPatch import app.revanced.patches.youtube.utils.returnyoutubedislike.shorts.ReturnYouTubeDislikeShortsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch -import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch +import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.util.getTargetIndexWithFieldReferenceType import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow @@ -30,7 +29,6 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch( description = "Shows the dislike count of videos using the Return YouTube Dislike API.", dependencies = setOf( LithoFilterPatch::class, - PlayerResponsePatch::class, ReturnYouTubeDislikeRollingNumberPatch::class, ReturnYouTubeDislikeShortsPatch::class, SettingsPatch::class, @@ -91,14 +89,22 @@ object ReturnYouTubeDislikePatch : BaseBytecodePatch( } } - VideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") - VideoIdPatch.injectPlayerResponseVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->preloadVideoId(Ljava/lang/String;Z)V") + // region Inject newVideoLoaded event handler to update dislikes when a new video is loaded. + VideoIdPatch.hookVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") + // Hook the player response video id, to start loading RYD sooner in the background. + VideoIdPatch.hookPlayerResponseVideoId("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->preloadVideoId(Ljava/lang/String;Z)V") + + // endregion + + // Player response video id is needed to search for the video ids in Shorts litho components. if (SettingsPatch.upward1834) { LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) - VideoIdPatch.injectPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V") + VideoIdPatch.hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V") } + // endregion + /** * Add ReVanced Extended Settings */ diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/sponsorblock/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/sponsorblock/SponsorBlockBytecodePatch.kt index 32610bbc3..ac0b5b576 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/sponsorblock/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/sponsorblock/SponsorBlockBytecodePatch.kt @@ -12,14 +12,13 @@ import app.revanced.patches.youtube.utils.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.youtube.utils.fingerprints.TotalTimeFingerprint import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.INTEGRATIONS_PATH -import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch import app.revanced.patches.youtube.utils.playercontrols.PlayerControlsPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.InsetOverlayViewLayout import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint import app.revanced.patches.youtube.utils.sponsorblock.fingerprints.SegmentPlaybackControllerFingerprint -import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch -import app.revanced.patches.youtube.utils.videoid.withoutshorts.VideoIdWithoutShortsPatch +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 @@ -34,11 +33,10 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Patch( dependencies = [ - OverrideSpeedHookPatch::class, PlayerControlsPatch::class, SharedResourceIdPatch::class, VideoIdPatch::class, - VideoIdWithoutShortsPatch::class + VideoInformationPatch::class ] ) object SponsorBlockBytecodePatch : BytecodePatch( @@ -60,13 +58,13 @@ object SponsorBlockBytecodePatch : BytecodePatch( override fun execute(context: BytecodeContext) { - VideoIdPatch.apply { + VideoInformationPatch.apply { // Hook the video time method videoTimeHook( INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR, "setVideoTime" ) - // Initialize SponsorBlock + // Initialize the player controller onCreateHook( INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR, "initialize" @@ -163,7 +161,7 @@ object SponsorBlockBytecodePatch : BytecodePatch( } } - // Inject VideoIdPatch - VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") + // Set current video id + VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videocpn/VideoCpnPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/videocpn/VideoCpnPatch.kt deleted file mode 100644 index 47918e1e6..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videocpn/VideoCpnPatch.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.patches.youtube.utils.videocpn - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint -import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch -import app.revanced.util.resultOrThrow - -@Patch(dependencies = [VideoIdPatch::class]) -object VideoCpnPatch : BytecodePatch( - setOf(OrganicPlaybackContextModelFingerprint) -) { - override fun execute(context: BytecodeContext) { - - insertMethod = OrganicPlaybackContextModelFingerprint.resultOrThrow().mutableMethod - - } - - private lateinit var insertMethod: MutableMethod - - internal fun injectCall( - methodDescriptor: String - ) { - insertMethod.addInstructions( - 2, - "invoke-static {p1}, $methodDescriptor" - ) - } -} - diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/VideoIdPatch.kt deleted file mode 100644 index 2541669fc..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/VideoIdPatch.kt +++ /dev/null @@ -1,247 +0,0 @@ -package app.revanced.patches.youtube.utils.videoid.general - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint -import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint -import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH -import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch -import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch -import app.revanced.patches.youtube.utils.videoid.general.fingerprint.PlayerControllerSetTimeReferenceFingerprint -import app.revanced.patches.youtube.utils.videoid.general.fingerprint.VideoIdFingerprint -import app.revanced.patches.youtube.utils.videoid.general.fingerprint.VideoIdParentFingerprint -import app.revanced.patches.youtube.utils.videoid.general.fingerprint.VideoLengthFingerprint -import app.revanced.util.getWalkerMethod -import app.revanced.util.resultOrThrow -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -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 = [ - PlayerTypeHookPatch::class, - PlayerResponsePatch::class - ] -) -object VideoIdPatch : BytecodePatch( - setOf( - OrganicPlaybackContextModelFingerprint, - PlayerControllerSetTimeReferenceFingerprint, - VideoEndFingerprint, - VideoIdParentFingerprint, - VideoLengthFingerprint - ) -) { - override fun execute(context: BytecodeContext) { - - VideoEndFingerprint.resultOrThrow().let { - playerInitMethod = - it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } - - // hook the player controller for use through integrations - onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize") - - it.mutableMethod.apply { - val seekHelperMethod = ImmutableMethod( - definingClass, - "seekTo", - listOf(ImmutableMethodParameter("J", annotations, "time")), - "Z", - AccessFlags.PUBLIC or AccessFlags.FINAL, - annotations, null, - MutableMethodImplementation(4) - ).toMutable() - - val seekSourceEnumType = parameterTypes[1].toString() - - seekHelperMethod.addInstructions( - 0, """ - sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType - invoke-virtual {p0, p1, p2, v0}, ${definingClass}->${name}(J$seekSourceEnumType)Z - move-result p1 - return p1 - """ - ) - it.mutableClass.methods.add(seekHelperMethod) - - val videoEndMethod = getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex + 1) - - videoEndMethod.apply { - addInstructionsWithLabels( - 0, """ - invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->videoEnded()Z - move-result v0 - if-eqz v0, :end - return-void - """, ExternalLabel("end", getInstruction(0)) - ) - } - } - } - - /** - * Set current video time - */ - PlayerControllerSetTimeReferenceFingerprint.resultOrThrow().let { - timeMethod = it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex) - } - - /** - * Hook the methods which set the time - */ - videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime") - - /** - * Set current video is livestream - */ - OrganicPlaybackContextModelFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - addInstruction( - 2, - "sput-boolean p2, $INTEGRATIONS_CLASS_DESCRIPTOR->isLiveStream:Z" - ) - } - } - - /** - * Set current video length - */ - VideoLengthFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - val startIndex = it.scanResult.patternScanResult!!.startIndex - val primaryRegister = getInstruction(startIndex).registerA - val secondaryRegister = primaryRegister + 1 - - addInstruction( - startIndex + 2, - "invoke-static {v$primaryRegister, v$secondaryRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V" - ) - } - } - - VideoIdParentFingerprint.resultOrThrow().let { parentResult -> - VideoIdFingerprint.also { - it.resolve( - context, - parentResult.classDef - ) - }.resultOrThrow().let { - it.mutableMethod.apply { - insertMethod = this - insertIndex = it.scanResult.patternScanResult!!.endIndex - videoIdRegister = getInstruction(insertIndex).registerA - } - offset++ // offset so setVideoId is called before any injected call - } - } - - injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") - injectPlayerResponseVideoId("$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. - PlayerResponsePatch += PlayerResponsePatch.Hook.PlayerBeforeVideoId( - "$INTEGRATIONS_CLASS_DESCRIPTOR->newPlayerParameter(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;" - ) - } - - const val INTEGRATIONS_CLASS_DESCRIPTOR = "$VIDEO_PATH/VideoInformation;" - - private var offset = 0 - private var playerInitInsertIndex = 4 - private var timeInitInsertIndex = 2 - - private var insertIndex: Int = 0 - private var videoIdRegister: Int = 0 - private lateinit var insertMethod: MutableMethod - private lateinit var playerInitMethod: MutableMethod - private lateinit var timeMethod: MutableMethod - - /** - * 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 - ) { - insertMethod.addInstructions( - insertIndex + offset, // move-result-object offset - "invoke-static {v$videoIdRegister}, $methodDescriptor" - ) - } - - /** - * Hooks the video id of every video when loaded. - * Supports all videos and functions in all situations. - * - * First parameter is the video id. - * Second parameter is if the video is a Short AND it is being opened or is currently playing. - * - * Hook is always called off the main thread. - * - * This hook is called as soon as the player response is parsed, - * and called before many other hooks are updated such as [PlayerTypeHookPatch]. - * - * Note: The video id returned here may not be the current video that's being played. - * It's common for multiple Shorts to load at once in preparation - * for the user swiping to the next Short. - * - * Be aware, this can be called multiple times for the same video id. - * - * @param methodDescriptor which method to call. Params must be `Ljava/lang/String;Z` - */ - internal fun injectPlayerResponseVideoId( - methodDescriptor: String - ) { - PlayerResponsePatch += PlayerResponsePatch.Hook.VideoId( - methodDescriptor - ) - } - - 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. - * - * Note: This hook is called very early and is called before the video id, video time, video length, - * and many other data fields are set. - * - * @param targetMethodClass The descriptor for the class to invoke when the player controller is created. - * @param targetMethodName The name of the static method to invoke when the player controller is created. - */ - internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) = - playerInitMethod.insert( - playerInitInsertIndex++, - "v0", - "$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" - ) - - /** - * Hook the video time. - * The hook is usually called once per second. - * - * @param targetMethodClass The descriptor for the static method to invoke when the player controller is created. - * @param targetMethodName The name of the static method to invoke when the player controller is created. - */ - internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) = - timeMethod.insertTimeHook( - timeInitInsertIndex++, - "$targetMethodClass->$targetMethodName(J)V" - ) -} - diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/VideoIdWithoutShortsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/VideoIdWithoutShortsPatch.kt deleted file mode 100644 index 55e070504..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/VideoIdWithoutShortsPatch.kt +++ /dev/null @@ -1,52 +0,0 @@ -package app.revanced.patches.youtube.utils.videoid.withoutshorts - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH -import app.revanced.patches.youtube.utils.videoid.withoutshorts.fingerprint.VideoIdWithoutShortsFingerprint -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 - -object VideoIdWithoutShortsPatch : BytecodePatch( - setOf(VideoIdWithoutShortsFingerprint) -) { - override fun execute(context: BytecodeContext) { - - VideoIdWithoutShortsFingerprint.resultOrThrow().let { - it.mutableMethod.apply { - insertMethod = this - insertIndex = getTargetIndex(Opcode.INVOKE_INTERFACE) - insertRegister = getInstruction(insertIndex + 1).registerA - } - } - - injectCall("$VIDEO_PATH/VideoInformation;->setVideoId(Ljava/lang/String;)V") - - } - - private var offset = 2 - - private var insertIndex: Int = 0 - private var insertRegister: Int = 0 - private lateinit var insertMethod: MutableMethod - - - /** - * 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 - ) { - insertMethod.addInstructions( - insertIndex + offset, // move-result-object offset - "invoke-static {v$insertRegister}, $methodDescriptor" - ) - } -} - diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/CustomPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/CustomPlaybackSpeedPatch.kt index 2fac2a7f8..5cea9f21c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/CustomPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/CustomPlaybackSpeedPatch.kt @@ -3,8 +3,8 @@ package app.revanced.patches.youtube.video.customspeed import app.revanced.patcher.data.ResourceContext import app.revanced.patches.youtube.flyoutpanel.oldspeedlayout.OldSpeedLayoutPatch import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE -import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch +import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.util.patch.BaseResourcePatch @Suppress("unused") @@ -14,8 +14,8 @@ object CustomPlaybackSpeedPatch : BaseResourcePatch( dependencies = setOf( CustomPlaybackSpeedBytecodePatch::class, OldSpeedLayoutPatch::class, - OverrideSpeedHookPatch::class, - SettingsPatch::class + SettingsPatch::class, + VideoInformationPatch::class ), compatiblePackages = COMPATIBLE_PACKAGE ) { diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt new file mode 100644 index 000000000..1c200562c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt @@ -0,0 +1,313 @@ +package app.revanced.patches.youtube.video.information + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patcher.util.smali.toInstructions +import app.revanced.patches.youtube.utils.fingerprints.OrganicPlaybackContextModelFingerprint +import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint +import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH +import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch +import app.revanced.patches.youtube.video.information.fingerprints.OnPlaybackSpeedItemClickFingerprint +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.VideoInformationPatchFingerprint +import app.revanced.patches.youtube.video.information.fingerprints.VideoLengthFingerprint +import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch +import app.revanced.patches.youtube.video.videoid.VideoIdPatch +import app.revanced.util.getTargetIndex +import app.revanced.util.getTargetIndexReversed +import app.revanced.util.getWalkerMethod +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.AccessFlags +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.immutable.ImmutableField +import com.android.tools.smali.dexlib2.immutable.ImmutableMethod +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter +import com.android.tools.smali.dexlib2.util.MethodUtil + +@Patch( + description = "Hooks YouTube to get information about the current playing video.", + dependencies = [ + PlayerResponseMethodHookPatch::class, + PlayerTypeHookPatch::class, + VideoIdPatch::class + ] +) +object VideoInformationPatch : BytecodePatch( + setOf( + OnPlaybackSpeedItemClickFingerprint, + OrganicPlaybackContextModelFingerprint, + PlaybackSpeedClassFingerprint, + PlayerControllerSetTimeReferenceFingerprint, + VideoEndFingerprint, + VideoInformationPatchFingerprint, + VideoLengthFingerprint + ) +) { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoInformation;" + + 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 + + // Used by other patches. + internal lateinit var speedSelectionInsertMethod: MutableMethod + + override fun execute(context: BytecodeContext) { + VideoEndFingerprint.resultOrThrow().let { + playerConstructorMethod = + it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } + + // hook the player controller for use through integrations + onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize") + + it.mutableMethod.apply { + val seekSourceEnumType = parameterTypes[1].toString() + + it.mutableClass.methods.add( + ImmutableMethod( + definingClass, + "seekTo", + listOf(ImmutableMethodParameter("J", annotations, "time")), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + annotations, + null, + ImmutableMethodImplementation( + 4, """ + sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType + invoke-virtual {p0, p1, p2, v0}, ${definingClass}->${name}(J$seekSourceEnumType)Z + move-result p1 + return p1 + """.toInstructions(), + null, + null + ) + ).toMutable() + ) + + val videoEndMethod = getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex + 1) + + videoEndMethod.apply { + addInstructionsWithLabels( + 0, """ + invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->videoEnded()Z + move-result v0 + if-eqz v0, :end + return-void + """, ExternalLabel("end", getInstruction(0)) + ) + } + } + } + + /** + * Set current video time method + */ + PlayerControllerSetTimeReferenceFingerprint.resultOrThrow().let { + videoTimeConstructorMethod = + it.getWalkerMethod(context, it.scanResult.patternScanResult!!.startIndex) + } + + /** + * Set current video time + */ + videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime") + + /** + * Set current video length + */ + VideoLengthFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val startIndex = it.scanResult.patternScanResult!!.startIndex + val primaryRegister = getInstruction(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;") + + /** + * Hook the user playback speed selection + */ + OnPlaybackSpeedItemClickFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + speedSelectionInsertMethod = this + val speedSelectionValueInstructionIndex = getTargetIndex(Opcode.IGET) + + val setPlaybackSpeedContainerClassFieldIndex = getTargetIndexReversed(speedSelectionValueInstructionIndex, Opcode.IGET_OBJECT) + val setPlaybackSpeedContainerClassFieldReference = + getInstruction(setPlaybackSpeedContainerClassFieldIndex).reference.toString() + + val setPlaybackSpeedClassFieldReference = + getInstruction(speedSelectionValueInstructionIndex + 1).reference.toString() + val setPlaybackSpeedMethodReference = + getInstruction(speedSelectionValueInstructionIndex + 2).reference.toString() + + it.mutableClass.methods.add( + ImmutableMethod( + definingClass, + "overridePlaybackSpeed", + listOf(ImmutableMethodParameter("F", annotations, null)), + "V", + AccessFlags.PUBLIC or AccessFlags.PUBLIC, + annotations, + null, + ImmutableMethodImplementation( + 4, """ + const/4 v0, 0x0 + cmpg-float v0, v3, v0 + if-lez v0, :ignore + + # Get the container class field. + iget-object v0, v2, $setPlaybackSpeedContainerClassFieldReference + + # Get the field from its class. + iget-object v1, v0, $setPlaybackSpeedClassFieldReference + + # Invoke setPlaybackSpeed on that class. + invoke-virtual {v1, v3}, $setPlaybackSpeedMethodReference + + :ignore + return-void + """.toInstructions(), null, null + ) + ).toMutable() + ) + + val walkerMethod = getWalkerMethod(context, speedSelectionValueInstructionIndex + 2) + + walkerMethod.apply { + addInstruction( + this.implementation!!.instructions.size - 1, + "invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlaybackSpeed(F)V" + ) + } + } + } + + PlaybackSpeedClassFingerprint.resultOrThrow().let { result -> + result.mutableMethod.apply { + val index = result.scanResult.patternScanResult!!.endIndex + val register = getInstruction(index).registerA + val playbackSpeedClass = this.returnType + replaceInstruction( + index, + "sput-object v$register, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackSpeedClass:$playbackSpeedClass" + ) + addInstruction( + index + 1, + "return-object v$register" + ) + + VideoInformationPatchFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + it.mutableClass.staticFields.add( + ImmutableField( + definingClass, + "playbackSpeedClass", + playbackSpeedClass, + AccessFlags.PUBLIC or AccessFlags.STATIC, + null, + annotations, + null + ).toMutable() + ) + + addInstructions( + 0, """ + sget-object v0, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackSpeedClass:$playbackSpeedClass + invoke-virtual {v0, p0}, $playbackSpeedClass->overridePlaybackSpeed(F)V + return-void + """ + ) + } + } + } + } + } + + 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. + * + * Note: This hook is called very early and is called before the video id, video time, video length, + * and many other data fields are set. + * + * @param targetMethodClass The descriptor for the class to invoke when the player controller is created. + * @param targetMethodName The name of the static method to invoke when the player controller is created. + */ + internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) = + playerConstructorMethod.insert( + playerConstructorInsertIndex++, + "v0", + "$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" + ) + + /** + * Hook the video time. + * The hook is usually called once per second. + * + * @param targetMethodClass The descriptor for the static method to invoke when the player controller is created. + * @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" + ) + + internal fun cpnHook(descriptor: String) = + videoCpnConstructorMethod.insert( + videoCpnConstructorInsertIndex++, + "p1, p2", + descriptor + ) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt new file mode 100644 index 000000000..58bd65e74 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.video.information.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.reference.FieldReference + +internal object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "V", + parameters = listOf("Landroid/widget/AdapterView;", "Landroid/view/View;", "I", "J"), + customFingerprint = { methodDef, _ -> + methodDef.name == "onItemClick" && methodDef.implementation?.instructions?.find { + it.opcode == Opcode.IGET_OBJECT && + it.getReference()!!.type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;" + } != null + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/SpeedClassFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlaybackSpeedClassFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/SpeedClassFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlaybackSpeedClassFingerprint.kt index a096857a1..2a72d9ebb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/SpeedClassFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlaybackSpeedClassFingerprint.kt @@ -1,11 +1,11 @@ -package app.revanced.patches.youtube.utils.overridespeed.fingerprints +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 import com.android.tools.smali.dexlib2.Opcode -internal object SpeedClassFingerprint : MethodFingerprint( +internal object PlaybackSpeedClassFingerprint : MethodFingerprint( returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/PlayerControllerSetTimeReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/PlayerControllerSetTimeReferenceFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt index 67e1ff37c..0e6c57de5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/PlayerControllerSetTimeReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.utils.videoid.general.fingerprint +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoInformationPatchFingerprint.kt similarity index 59% rename from src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedPatchFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoInformationPatchFingerprint.kt index 232dbcd59..759f6bc55 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/overridespeed/fingerprints/PlaybackSpeedPatchFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoInformationPatchFingerprint.kt @@ -1,16 +1,16 @@ -package app.revanced.patches.youtube.utils.overridespeed.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH import com.android.tools.smali.dexlib2.AccessFlags -internal object PlaybackSpeedPatchFingerprint : MethodFingerprint( +internal object VideoInformationPatchFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("F"), customFingerprint = { methodDef, _ -> - methodDef.definingClass == "$VIDEO_PATH/PlaybackSpeedPatch;" - && methodDef.name == "overrideSpeed" + methodDef.definingClass == "$VIDEO_PATH/VideoInformation;" + && methodDef.name == "overridePlaybackSpeed" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoLengthFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoLengthFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoLengthFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoLengthFingerprint.kt index a01fe71d7..db2d60174 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoLengthFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoLengthFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.utils.videoid.general.fingerprint +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.extensions.or import app.revanced.util.fingerprint.LiteralValueFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt new file mode 100644 index 000000000..3d79f2073 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -0,0 +1,106 @@ +package app.revanced.patches.youtube.video.playerresponse + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +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.youtube.video.playerresponse.fingerprint.PlayerParameterBuilderFingerprint +import app.revanced.util.resultOrThrow +import java.io.Closeable + +object PlayerResponseMethodHookPatch : + BytecodePatch(setOf(PlayerParameterBuilderFingerprint)), + Closeable, + MutableSet by mutableSetOf() { + + // Parameter numbers of the patched method. + private var PARAMETER_VIDEO_ID = 1 + private var PARAMETER_PLAYER_PARAMETER = 3 + private var PARAMETER_PLAYLIST_ID = 4 + private var PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11 + + private var freeRegister = 0 + private var shouldApplyNewMethod = false + + private lateinit var playerResponseMethod: MutableMethod + + override fun execute(context: BytecodeContext) { + playerResponseMethod = PlayerParameterBuilderFingerprint.resultOrThrow().mutableMethod + + playerResponseMethod.apply { + freeRegister = implementation!!.registerCount - parameters.size - 2 + shouldApplyNewMethod = freeRegister > 2 + if (shouldApplyNewMethod) { + PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = freeRegister + PARAMETER_PLAYLIST_ID = freeRegister - 1 + PARAMETER_PLAYER_PARAMETER = freeRegister - 2 + PARAMETER_VIDEO_ID = freeRegister - 3 + } + } + } + + override fun close() { + fun hookVideoId(hook: Hook) { + val instruction = + if (shouldApplyNewMethod) + "invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook" + else + "invoke-static {p$PARAMETER_VIDEO_ID, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook" + + playerResponseMethod.addInstruction( + 0, instruction + ) + } + + fun hookPlayerParameter(hook: Hook) { + val instruction = + if (shouldApplyNewMethod) + """ + invoke-static {v$PARAMETER_VIDEO_ID, v$PARAMETER_PLAYER_PARAMETER, 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 + move-result-object p$PARAMETER_PLAYER_PARAMETER + """ + + playerResponseMethod.addInstructions( + 0, + instruction + ) + } + + // Reverse the order in order to preserve insertion order of the hooks. + val beforeVideoIdHooks = filterIsInstance().asReversed() + val videoIdHooks = filterIsInstance().asReversed() + val afterVideoIdHooks = filterIsInstance().asReversed() + + // Add the hooks in this specific order as they insert instructions at the beginning of the method. + afterVideoIdHooks.forEach(::hookPlayerParameter) + videoIdHooks.forEach(::hookVideoId) + beforeVideoIdHooks.forEach(::hookPlayerParameter) + + if (shouldApplyNewMethod) { + playerResponseMethod.addInstructions( + 0, """ + move-object v$PARAMETER_VIDEO_ID, p1 + move-object v$PARAMETER_PLAYER_PARAMETER, p3 + move-object v$PARAMETER_PLAYLIST_ID, p4 + move/from16 v$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING, p11 + """ + ) + } + } + + internal abstract class Hook(private val methodDescriptor: String) { + internal class VideoId(methodDescriptor: String) : Hook(methodDescriptor) + + internal class PlayerParameter(methodDescriptor: String) : Hook(methodDescriptor) + internal class PlayerParameterBeforeVideoId(methodDescriptor: String) : Hook(methodDescriptor) + + override fun toString() = methodDescriptor + } +} + diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/fingerprints/PlayerParameterBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/fingerprints/PlayerParameterBuilderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt index eb7e3c18f..2fad7540b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/playerresponse/fingerprints/PlayerParameterBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/fingerprint/PlayerParameterBuilderFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.utils.playerresponse.fingerprints +package app.revanced.patches.youtube.video.playerresponse.fingerprint import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint @@ -11,7 +11,7 @@ internal object PlayerParameterBuilderFingerprint : MethodFingerprint( "Ljava/lang/String;", // VideoId. "[B", "Ljava/lang/String;", // Player parameters proto buffer. - "Ljava/lang/String;", + "Ljava/lang/String;", // PlaylistId. "I", "I", "Ljava/util/Set;", diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt index 172eac490..3ae3e4969 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/VideoQualityPatch.kt @@ -4,18 +4,17 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.PatchException -import app.revanced.patches.youtube.utils.fingerprints.NewVideoQualityChangedFingerprint -import app.revanced.patches.youtube.utils.fingerprints.VideoQualitySetterFingerprint +import app.revanced.patches.youtube.utils.fingerprints.QualityChangedFromRecyclerViewFingerprint +import app.revanced.patches.youtube.utils.fingerprints.QualitySetterFingerprint import app.revanced.patches.youtube.utils.fix.shortsplayback.ShortsPlaybackPatch import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH import app.revanced.patches.youtube.utils.overridequality.OverrideQualityHookPatch -import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch.contexts -import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch -import app.revanced.patches.youtube.utils.videoid.withoutshorts.VideoIdWithoutShortsPatch +import app.revanced.patches.youtube.video.information.VideoInformationPatch +import app.revanced.patches.youtube.video.videoid.VideoIdPatch import app.revanced.util.copyXmlNode import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow @@ -27,22 +26,27 @@ object VideoQualityPatch : BaseBytecodePatch( description = "Adds an option to set the default video quality.", dependencies = setOf( OverrideQualityHookPatch::class, - OverrideSpeedHookPatch::class, PlayerTypeHookPatch::class, SettingsPatch::class, ShortsPlaybackPatch::class, VideoIdPatch::class, - VideoIdWithoutShortsPatch::class + VideoInformationPatch::class ), compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( - NewVideoQualityChangedFingerprint, - VideoQualitySetterFingerprint + QualityChangedFromRecyclerViewFingerprint, + QualitySetterFingerprint ) ) { + private const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoQualityPatch;" + private const val INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR = + "$VIDEO_PATH/ReloadVideoPatch;" + override fun execute(context: BytecodeContext) { - NewVideoQualityChangedFingerprint.resultOrThrow().let { + // Remember video quality from recyclerview (litho view). + QualityChangedFromRecyclerViewFingerprint.resultOrThrow().let { it.mutableMethod.apply { val index = it.scanResult.patternScanResult!!.startIndex val qualityRegister = getInstruction(index).registerA @@ -55,7 +59,7 @@ object VideoQualityPatch : BaseBytecodePatch( } } - VideoQualitySetterFingerprint.resultOrThrow().let { + QualitySetterFingerprint.resultOrThrow().let { val onItemClickMethod = it.mutableClass.methods.find { method -> method.name == "onItemClick" } @@ -69,10 +73,8 @@ object VideoQualityPatch : BaseBytecodePatch( } ?: throw PatchException("Failed to find onItemClick method") } - VideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") - VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") - - VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") + VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + VideoIdPatch.hookBackgroundPlayVideoId("$INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V") /** * Copy arrays @@ -94,9 +96,4 @@ object VideoQualityPatch : BaseBytecodePatch( SettingsPatch.updatePatchStatus("Default video quality") } - - private const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = - "$VIDEO_PATH/VideoQualityPatch;" - private const val INTEGRATIONS_RELOAD_VIDEO_CLASS_DESCRIPTOR = - "$VIDEO_PATH/ReloadVideoPatch;" } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt index a1e4842c0..72e133eb5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt @@ -4,34 +4,35 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patches.youtube.utils.fingerprints.NewVideoQualityChangedFingerprint +import app.revanced.patches.youtube.utils.fingerprints.QualityChangedFromRecyclerViewFingerprint import app.revanced.patches.youtube.utils.fingerprints.VideoEndFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH import app.revanced.patches.youtube.utils.integrations.Constants.VIDEO_PATH -import app.revanced.patches.youtube.utils.overridespeed.OverrideSpeedHookPatch import app.revanced.patches.youtube.utils.settings.SettingsPatch -import app.revanced.patches.youtube.utils.videocpn.VideoCpnPatch -import app.revanced.patches.youtube.video.speed.fingerprints.NewPlaybackSpeedChangedFingerprint +import app.revanced.patches.youtube.video.information.VideoInformationPatch +import app.revanced.patches.youtube.video.information.VideoInformationPatch.speedSelectionInsertMethod +import app.revanced.patches.youtube.video.speed.fingerprints.PlaybackSpeedChangedFromRecyclerViewFingerprint import app.revanced.patches.youtube.video.speed.fingerprints.PlaybackSpeedInitializeFingerprint +import app.revanced.util.getTargetIndex import app.revanced.util.patch.BaseBytecodePatch import app.revanced.util.resultOrThrow import app.revanced.util.updatePatchStatus -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Suppress("unused") object PlaybackSpeedPatch : BaseBytecodePatch( name = "Default playback speed", description = "Adds an option to set the default playback speed.", dependencies = setOf( - OverrideSpeedHookPatch::class, SettingsPatch::class, - VideoCpnPatch::class + VideoInformationPatch::class ), compatiblePackages = COMPATIBLE_PACKAGE, fingerprints = setOf( - NewVideoQualityChangedFingerprint, + QualityChangedFromRecyclerViewFingerprint, VideoEndFingerprint ) ) { @@ -40,24 +41,27 @@ object PlaybackSpeedPatch : BaseBytecodePatch( override fun execute(context: BytecodeContext) { - NewVideoQualityChangedFingerprint.resultOrThrow().let { parentResult -> - NewPlaybackSpeedChangedFingerprint.also { - it.resolve( - context, - parentResult.classDef - ) - }.resultOrThrow().let { result -> - arrayOf(result, OverrideSpeedHookPatch.playbackSpeedChangedResult).forEach { - it.mutableMethod.apply { - val index = it.scanResult.patternScanResult!!.endIndex - val register = getInstruction(index).registerD + PlaybackSpeedChangedFromRecyclerViewFingerprint.resolve( + context, + QualityChangedFromRecyclerViewFingerprint.resultOrThrow().classDef + ) - addInstruction( - index, - "invoke-static {v$register}, $INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->userChangedSpeed(F)V" - ) - } - } + val newMethod = PlaybackSpeedChangedFromRecyclerViewFingerprint.resultOrThrow().mutableMethod + + arrayOf( + newMethod, + speedSelectionInsertMethod + ).forEach { + it.apply { + val speedSelectionValueInstructionIndex = getTargetIndex(Opcode.IGET) + val speedSelectionValueRegister = + getInstruction(speedSelectionValueInstructionIndex).registerA + + addInstruction( + speedSelectionValueInstructionIndex + 1, + "invoke-static {v$speedSelectionValueRegister}, " + + "$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->userSelectedPlaybackSpeed(F)V" + ) } } @@ -82,7 +86,7 @@ object PlaybackSpeedPatch : BaseBytecodePatch( } } - VideoCpnPatch.injectCall("$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + VideoInformationPatch.cpnHook("$INTEGRATIONS_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Z)V") /** * Add settings diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/NewPlaybackSpeedChangedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/PlaybackSpeedChangedFromRecyclerViewFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/NewPlaybackSpeedChangedFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/PlaybackSpeedChangedFromRecyclerViewFingerprint.kt index ff630556c..4d224c251 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/NewPlaybackSpeedChangedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/fingerprints/PlaybackSpeedChangedFromRecyclerViewFingerprint.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 -internal object NewPlaybackSpeedChangedFingerprint : MethodFingerprint( +internal object PlaybackSpeedChangedFromRecyclerViewFingerprint : MethodFingerprint( returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt new file mode 100644 index 000000000..2e58a71dd --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt @@ -0,0 +1,136 @@ +package app.revanced.patches.youtube.video.videoid + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch +import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdFingerprint +import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdParentFingerprint +import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch +import app.revanced.patches.youtube.video.videoid.fingerprints.VideoIdFingerprintBackgroundPlay +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( + description = "Hooks to detect when the video id changes", + dependencies = [PlayerResponseMethodHookPatch::class], +) +object VideoIdPatch : BytecodePatch( + setOf( + VideoIdParentFingerprint, + VideoIdFingerprintBackgroundPlay + ) +) { + 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) { + + /** + * Supplies the method and register index of the video id register. + * + * @param consumer Consumer that receives the method, insert index and video id register index. + */ + fun MethodFingerprint.setFields(consumer: (MutableMethod, Int, Int) -> Unit) = resultOrThrow().let { result -> + val videoIdRegisterIndex = result.scanResult.patternScanResult!!.endIndex + + result.mutableMethod.let { + val videoIdRegister = it.getInstruction(videoIdRegisterIndex).registerA + val insertIndex = videoIdRegisterIndex + 1 + consumer(it, insertIndex, videoIdRegister) + } + } + + VideoIdFingerprint.resolve(context, VideoIdParentFingerprint.resultOrThrow().classDef) + + VideoIdFingerprint.setFields { method, index, register -> + videoIdMethod = method + videoIdInsertIndex = index + videoIdRegister = register + } + + VideoIdFingerprintBackgroundPlay.resultOrThrow().let { + it.mutableMethod.apply { + backgroundPlaybackMethod = this + backgroundPlaybackInsertIndex = getTargetIndex(Opcode.INVOKE_INTERFACE) + 2 + backgroundPlaybackVideoIdRegister = getInstruction(backgroundPlaybackInsertIndex - 1).registerA + } + } + } + + /** + * Hooks the new video id when the video changes. + * + * Supports all videos (regular videos and Shorts). + * + * _Does not function if playing in the background with no video visible_. + * + * Be aware, this can be called multiple times for the same video id. + * + * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` + */ + fun hookVideoId( + methodDescriptor: String + ) = videoIdMethod.addInstruction( + videoIdInsertIndex++, + "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. + * + * First parameter is the video id. + * Second parameter is if the video is a Short AND it is being opened or is currently playing. + * + * Hook is always called off the main thread. + * + * This hook is called as soon as the player response is parsed, + * and called before many other hooks are updated such as [PlayerTypeHookPatch]. + * + * Note: The video id returned here may not be the current video that's being played. + * 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. + * + * Be aware, this can be called multiple times for the same video id. + * + * @param methodDescriptor which method to call. Params must be `Ljava/lang/String;Z` + */ + fun hookPlayerResponseVideoId(methodDescriptor: String) { + PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.VideoId( + methodDescriptor + ) + } +} + diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoIdFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdFingerprint.kt index 89bbefaf5..7158d20dc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.utils.videoid.general.fingerprint +package app.revanced.patches.youtube.video.videoid.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/fingerprint/VideoIdWithoutShortsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdFingerprintBackgroundPlay.kt similarity index 79% rename from src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/fingerprint/VideoIdWithoutShortsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdFingerprintBackgroundPlay.kt index 4430a0a9c..643b25562 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/withoutshorts/fingerprint/VideoIdWithoutShortsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdFingerprintBackgroundPlay.kt @@ -1,11 +1,14 @@ -package app.revanced.patches.youtube.utils.videoid.withoutshorts.fingerprint +package app.revanced.patches.youtube.video.videoid.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 -internal object VideoIdWithoutShortsFingerprint : MethodFingerprint( +/** + * Renamed from VideoIdWithoutShortsFingerprint + */ +internal object VideoIdFingerprintBackgroundPlay : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.DECLARED_SYNCHRONIZED, parameters = listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoIdParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdParentFingerprint.kt similarity index 79% rename from src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoIdParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdParentFingerprint.kt index e0f814255..cec98bfca 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/videoid/general/fingerprint/VideoIdParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprints/VideoIdParentFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.utils.videoid.general.fingerprint +package app.revanced.patches.youtube.video.videoid.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint