diff --git a/src/main/kotlin/app/revanced/patches/music/utils/overridequality/fingerprints/VideoQualityListFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/utils/overridequality/fingerprints/VideoQualityListFingerprint.kt new file mode 100644 index 000000000..6ce153fe3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/utils/overridequality/fingerprints/VideoQualityListFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.music.utils.overridequality.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch.Companion.QualityAuto +import app.revanced.util.bytecode.isWideLiteralExists +import com.android.tools.smali.dexlib2.Opcode + +object VideoQualityListFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L"), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, + Opcode.RETURN_VOID + ), + customFingerprint = { methodDef, _ -> methodDef.isWideLiteralExists(QualityAuto) } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/utils/overridequality/fingerprints/VideoQualityPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/utils/overridequality/fingerprints/VideoQualityPatchFingerprint.kt new file mode 100644 index 000000000..bb36e38de --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/utils/overridequality/fingerprints/VideoQualityPatchFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.music.utils.overridequality.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +object VideoQualityPatchFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC, + parameters = listOf("I"), + customFingerprint = { methodDef, _ -> + methodDef.definingClass == "Lapp/revanced/music/patches/video/VideoQualityPatch;" + && methodDef.name == "overrideQuality" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/utils/overridequality/patch/OverrideQualityHookPatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/overridequality/patch/OverrideQualityHookPatch.kt new file mode 100644 index 000000000..76c5e9fb1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/utils/overridequality/patch/OverrideQualityHookPatch.kt @@ -0,0 +1,88 @@ +package app.revanced.patches.music.utils.overridequality.patch + +import app.revanced.extensions.exception +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.or +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patches.music.utils.overridequality.fingerprints.VideoQualityListFingerprint +import app.revanced.patches.music.utils.overridequality.fingerprints.VideoQualityPatchFingerprint +import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch +import app.revanced.util.integrations.Constants.MUSIC_VIDEO_PATH +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.immutable.ImmutableField +import com.android.tools.smali.dexlib2.util.MethodUtil + +@DependsOn([SharedResourceIdPatch::class]) +class OverrideQualityHookPatch : BytecodePatch( + listOf( + VideoQualityListFingerprint, + VideoQualityPatchFingerprint + ) +) { + override fun execute(context: BytecodeContext) { + + VideoQualityListFingerprint.result?.let { + val constructorMethod = it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } + val overrideMethod = it.mutableClass.methods.find { method -> method.parameterTypes.first() == "I" } + + QUALITY_CLASS = it.method.definingClass + QUALITY_METHOD = overrideMethod?.name + ?:throw PatchException("Failed to find hook method") + + constructorMethod.apply { + addInstruction( + 2, + "sput-object p0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qualityClass:$QUALITY_CLASS" + ) + } + + it.mutableMethod.apply { + val listIndex = it.scanResult.patternScanResult!!.startIndex + val listRegister = getInstruction(listIndex).registerD + + addInstruction( + listIndex, + "invoke-static {v$listRegister}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQualityList([Ljava/lang/Object;)V" + ) + } + } ?: throw VideoQualityListFingerprint.exception + + VideoQualityPatchFingerprint.result?.let { + it.mutableMethod.apply { + it.mutableClass.staticFields.add( + ImmutableField( + definingClass, + "qualityClass", + QUALITY_CLASS, + AccessFlags.PUBLIC or AccessFlags.STATIC, + null, + annotations, + null + ).toMutable() + ) + + addInstructions( + 0, """ + sget-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qualityClass:$QUALITY_CLASS + invoke-virtual {v0, p0}, $QUALITY_CLASS->$QUALITY_METHOD(I)V + """ + ) + } + } ?: throw VideoQualityPatchFingerprint.exception + } + + internal companion object { + const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = + "$MUSIC_VIDEO_PATH/VideoQualityPatch;" + + private lateinit var QUALITY_CLASS: String + private lateinit var QUALITY_METHOD: String + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/utils/resourceid/patch/SharedResourceIdPatch.kt b/src/main/kotlin/app/revanced/patches/music/utils/resourceid/patch/SharedResourceIdPatch.kt index bc986fa63..f23cd16d7 100644 --- a/src/main/kotlin/app/revanced/patches/music/utils/resourceid/patch/SharedResourceIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/utils/resourceid/patch/SharedResourceIdPatch.kt @@ -29,7 +29,7 @@ class SharedResourceIdPatch : ResourcePatch { var MusicMenuLikeButtons: Long = -1 var NamesInactiveAccountThumbnailSize: Long = -1 var PrivacyTosFooter: Long = -1 - var QualityTitle: Long = -1 + var QualityAuto: Long = -1 var Text1: Long = -1 var ToolTipContentView: Long = -1 var TosFooter: Long = -1 @@ -55,7 +55,7 @@ class SharedResourceIdPatch : ResourcePatch { MusicMenuLikeButtons = find(LAYOUT, "music_menu_like_buttons") NamesInactiveAccountThumbnailSize = find(DIMEN, "names_inactive_account_thumbnail_size") PrivacyTosFooter = find(ID, "privacy_tos_footer") - QualityTitle = find(STRING, "quality_title") + QualityAuto = find(STRING, "quality_auto") Text1 = find(ID, "text1") ToolTipContentView = find(LAYOUT, "tooltip_content_view") TosFooter = find(ID, "tos_footer") diff --git a/src/main/kotlin/app/revanced/patches/music/video/quality/fingerprints/MusicVideoQualitySettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/quality/fingerprints/MusicVideoQualitySettingsFingerprint.kt deleted file mode 100644 index 8b4af0fca..000000000 --- a/src/main/kotlin/app/revanced/patches/music/video/quality/fingerprints/MusicVideoQualitySettingsFingerprint.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.music.video.quality.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object MusicVideoQualitySettingsFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("[L", "I", "Z"), - opcodes = listOf( - Opcode.IPUT_OBJECT, - Opcode.IPUT - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/video/quality/fingerprints/MusicVideoQualitySettingsParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/video/quality/fingerprints/MusicVideoQualitySettingsParentFingerprint.kt deleted file mode 100644 index f99d7e1d7..000000000 --- a/src/main/kotlin/app/revanced/patches/music/video/quality/fingerprints/MusicVideoQualitySettingsParentFingerprint.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.music.video.quality.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch.Companion.QualityTitle -import app.revanced.util.bytecode.isWideLiteralExists -import com.android.tools.smali.dexlib2.AccessFlags - -object MusicVideoQualitySettingsParentFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - parameters = listOf("L"), - customFingerprint = { methodDef, _ -> methodDef.isWideLiteralExists(QualityTitle) } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/video/quality/patch/VideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/music/video/quality/patch/VideoQualityPatch.kt index 45c6f1115..62d13b684 100644 --- a/src/main/kotlin/app/revanced/patches/music/video/quality/patch/VideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/video/quality/patch/VideoQualityPatch.kt @@ -1,49 +1,37 @@ package app.revanced.patches.music.video.quality.patch import app.revanced.extensions.exception -import app.revanced.extensions.findMutableMethodOf import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name 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.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.music.utils.annotations.MusicCompatibility -import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch +import app.revanced.patches.music.utils.overridequality.patch.OverrideQualityHookPatch import app.revanced.patches.music.utils.settings.resource.patch.SettingsPatch import app.revanced.patches.music.video.information.patch.VideoInformationPatch -import app.revanced.patches.music.video.quality.fingerprints.MusicVideoQualitySettingsFingerprint -import app.revanced.patches.music.video.quality.fingerprints.MusicVideoQualitySettingsParentFingerprint import app.revanced.patches.music.video.quality.fingerprints.UserQualityChangeFingerprint import app.revanced.util.enum.CategoryType import app.revanced.util.integrations.Constants.MUSIC_VIDEO_PATH -import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.iface.reference.Reference @Patch @Name("Remember video quality") @Description("Save the video quality value whenever you change the video quality.") @DependsOn( [ + OverrideQualityHookPatch::class, SettingsPatch::class, - SharedResourceIdPatch::class, VideoInformationPatch::class ] ) @MusicCompatibility class VideoQualityPatch : BytecodePatch( - listOf( - MusicVideoQualitySettingsParentFingerprint, - UserQualityChangeFingerprint - ) + listOf(UserQualityChangeFingerprint) ) { override fun execute(context: BytecodeContext) { @@ -57,61 +45,19 @@ class VideoQualityPatch : BytecodePatch( )!! .mutableClass - for (method in qualityChangedClass.methods) { - qualityChangedClass.findMutableMethodOf(method).apply { - if (this.name == "onItemClick") { - for ((index, instruction) in implementation!!.instructions.withIndex()) { - if (instruction.opcode != Opcode.INVOKE_INTERFACE) continue + val onItemClickMethod = qualityChangedClass.methods.find { method -> method.name == "onItemClick" } - qIndexMethodName = - ((getInstruction(index).reference) as MethodReference).name + onItemClickMethod?.apply { + val listItemIndexParameter = 3 - val qIndexMethodClass = - ((getInstruction(index).reference) as MethodReference).definingClass - - for (qualityReferenceIndex in index downTo 0) { - if (getInstruction(qualityReferenceIndex).opcode != Opcode.IGET_OBJECT) continue - - val targetReference = - getInstruction(qualityReferenceIndex).reference - - if (!targetReference.toString() - .endsWith(qIndexMethodClass) - ) continue - - qualityReference = targetReference - break - } - - addInstruction( - 0, - "invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V" - ) - break - } - } - } - } + addInstruction( + 0, + "invoke-static {p$listItemIndexParameter}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V" + ) + } ?: throw PatchException("Failed to find onItemClick method") } } ?: throw UserQualityChangeFingerprint.exception - MusicVideoQualitySettingsParentFingerprint.result?.let { parentResult -> - MusicVideoQualitySettingsFingerprint.also { - it.resolve( - context, - parentResult.classDef - ) - }.result?.mutableMethod?.addInstructions( - 0, """ - const-string v0, "$qIndexMethodName" - sput-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qIndexMethod:Ljava/lang/String; - iget-object v0, p0, $qualityReference - invoke-static {p1, p2, v0}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;)I - move-result p2 - """ - ) ?: throw MusicVideoQualitySettingsFingerprint.exception - } ?: throw MusicVideoQualitySettingsParentFingerprint.exception - VideoInformationPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") SettingsPatch.addMusicPreference( @@ -125,8 +71,5 @@ class VideoQualityPatch : BytecodePatch( private companion object { const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = "$MUSIC_VIDEO_PATH/VideoQualityPatch;" - - private lateinit var qIndexMethodName: String - private lateinit var qualityReference: Reference } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityListFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityListFingerprint.kt new file mode 100644 index 000000000..7e5431de0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityListFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.utils.overridequality.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch.Companion.QualityAuto +import app.revanced.util.bytecode.isWideLiteralExists +import com.android.tools.smali.dexlib2.Opcode + +object VideoQualityListFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L"), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, + Opcode.RETURN_VOID + ), + customFingerprint = { methodDef, _ -> methodDef.isWideLiteralExists(QualityAuto) } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityPatchFingerprint.kt new file mode 100644 index 000000000..0d974d454 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityPatchFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.utils.overridequality.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +object VideoQualityPatchFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf("I"), + customFingerprint = { methodDef, _ -> + methodDef.definingClass == "Lapp/revanced/integrations/patches/video/VideoQualityPatch;" + && methodDef.name == "overrideQuality" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySettingsParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityTextFingerprint.kt similarity index 66% rename from src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySettingsParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityTextFingerprint.kt index c93a90c2b..db4c8480a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySettingsParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/fingerprints/VideoQualityTextFingerprint.kt @@ -1,18 +1,18 @@ -package app.revanced.patches.youtube.video.quality.fingerprints +package app.revanced.patches.youtube.utils.overridequality.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -object VideoQualitySettingsParentFingerprint : MethodFingerprint( +object VideoQualityTextFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("[L", "I", "Z"), opcodes = listOf( - Opcode.IF_NE, - Opcode.IGET, - Opcode.IF_EQ + Opcode.IF_GE, + Opcode.AGET_OBJECT, + Opcode.IGET_OBJECT ), strings = listOf("menu_item_video_quality") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/patch/OverrideQualityHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/patch/OverrideQualityHookPatch.kt new file mode 100644 index 000000000..5409901eb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/overridequality/patch/OverrideQualityHookPatch.kt @@ -0,0 +1,107 @@ +package app.revanced.patches.youtube.utils.overridequality.patch + +import app.revanced.extensions.exception +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.or +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch +import app.revanced.patches.youtube.utils.overridequality.fingerprints.VideoQualityListFingerprint +import app.revanced.patches.youtube.utils.overridequality.fingerprints.VideoQualityPatchFingerprint +import app.revanced.patches.youtube.utils.overridequality.fingerprints.VideoQualityTextFingerprint +import app.revanced.util.integrations.Constants.INTEGRATIONS_PATH +import app.revanced.util.integrations.Constants.VIDEO_PATH +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.immutable.ImmutableField +import com.android.tools.smali.dexlib2.util.MethodUtil + +@DependsOn([SharedResourceIdPatch::class]) +class OverrideQualityHookPatch : BytecodePatch( + listOf( + VideoQualityListFingerprint, + VideoQualityPatchFingerprint, + VideoQualityTextFingerprint + ) +) { + override fun execute(context: BytecodeContext) { + + VideoQualityListFingerprint.result?.let { + val constructorMethod = it.mutableClass.methods.first { method -> MethodUtil.isConstructor(method) } + val overrideMethod = it.mutableClass.methods.find { method -> method.parameterTypes.first() == "I" } + + QUALITY_CLASS = it.method.definingClass + QUALITY_METHOD = overrideMethod?.name + ?:throw PatchException("Failed to find hook method") + + constructorMethod.apply { + addInstruction( + 2, + "sput-object p0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qualityClass:$QUALITY_CLASS" + ) + } + + it.mutableMethod.apply { + val listIndex = it.scanResult.patternScanResult!!.startIndex + val listRegister = getInstruction(listIndex).registerD + + addInstruction( + listIndex, + "invoke-static {v$listRegister}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQualityList([Ljava/lang/Object;)V" + ) + } + } ?: throw VideoQualityListFingerprint.exception + + VideoQualityPatchFingerprint.result?.let { + it.mutableMethod.apply { + it.mutableClass.staticFields.add( + ImmutableField( + definingClass, + "qualityClass", + QUALITY_CLASS, + AccessFlags.PUBLIC or AccessFlags.STATIC, + null, + annotations, + null + ).toMutable() + ) + + addInstructions( + 0, """ + sget-object v0, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->qualityClass:$QUALITY_CLASS + invoke-virtual {v0, p0}, $QUALITY_CLASS->$QUALITY_METHOD(I)V + """ + ) + } + } ?: throw VideoQualityPatchFingerprint.exception + + VideoQualityTextFingerprint.result?.let { + it.mutableMethod.apply { + val textIndex = it.scanResult.patternScanResult!!.endIndex + val textRegister = getInstruction(textIndex).registerA + + addInstruction( + textIndex + 1, + "sput-object v$textRegister, $INTEGRATIONS_VIDEO_HELPER_CLASS_DESCRIPTOR->currentQuality:Ljava/lang/String;" + ) + } + } ?: throw VideoQualityTextFingerprint.exception + } + + internal companion object { + const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoQualityPatch;" + + const val INTEGRATIONS_VIDEO_HELPER_CLASS_DESCRIPTOR = + "$INTEGRATIONS_PATH/utils/VideoHelpers;" + + private lateinit var QUALITY_CLASS: String + private lateinit var QUALITY_METHOD: String + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt index 3e2a1bd2e..17184e5e9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/patch/SharedResourceIdPatch.kt @@ -53,6 +53,7 @@ class SharedResourceIdPatch : ResourcePatch { var LiveChatButton: Long = -1 var MusicAppDeeplinkButtonView: Long = -1 var PosterArtWidthDefault: Long = -1 + var QualityAuto: Long = -1 var QuickActionsElementContainer: Long = -1 var ReelDynRemix: Long = -1 var ReelDynShare: Long = -1 @@ -130,6 +131,7 @@ class SharedResourceIdPatch : ResourcePatch { LiveChatButton = find(ID, "live_chat_overlay_button") MusicAppDeeplinkButtonView = find(ID, "music_app_deeplink_button_view") PosterArtWidthDefault = find(DIMEN, "poster_art_width_default") + QualityAuto = find(STRING, "quality_auto") QuickActionsElementContainer = find(ID, "quick_actions_element_container") ReelDynRemix = find(ID, "reel_dyn_remix") ReelDynShare = find(ID, "reel_dyn_share") diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt deleted file mode 100644 index 9d59ba083..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.youtube.video.quality.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object VideoQualityReferenceFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("L"), - opcodes = listOf( - Opcode.IPUT_OBJECT, - Opcode.RETURN_VOID - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySettingsFingerprint.kt deleted file mode 100644 index 4de888f5a..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySettingsFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.video.quality.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object VideoQualitySettingsFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("L"), - opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.IGET_OBJECT - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt deleted file mode 100644 index 27e26314d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.video.quality.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -object VideoUserQualityChangeFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef, _ -> methodDef.name == "onItemClick" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/VideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/VideoQualityPatch.kt index fed0989b5..63bcdf768 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/VideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/VideoQualityPatch.kt @@ -5,35 +5,31 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name 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.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.youtube.utils.annotations.YouTubeCompatibility import app.revanced.patches.youtube.utils.fingerprints.NewFlyoutPanelOnClickListenerFingerprint +import app.revanced.patches.youtube.utils.overridequality.patch.OverrideQualityHookPatch import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch.Companion.contexts import app.revanced.patches.youtube.utils.videoid.general.patch.VideoIdPatch import app.revanced.patches.youtube.utils.videoid.withoutshorts.patch.VideoIdWithoutShortsPatch import app.revanced.patches.youtube.video.quality.fingerprints.NewVideoQualityChangedFingerprint -import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualityReferenceFingerprint import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySetterFingerprint -import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySettingsFingerprint -import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySettingsParentFingerprint -import app.revanced.patches.youtube.video.quality.fingerprints.VideoUserQualityChangeFingerprint import app.revanced.util.integrations.Constants.VIDEO_PATH import app.revanced.util.resources.ResourceUtils.copyXmlNode -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Patch @Name("Default video quality") @Description("Adds ability to set default video quality settings.") @DependsOn( [ + OverrideQualityHookPatch::class, VideoIdPatch::class, VideoIdWithoutShortsPatch::class, SettingsPatch::class @@ -43,8 +39,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference class VideoQualityPatch : BytecodePatch( listOf( NewFlyoutPanelOnClickListenerFingerprint, - VideoQualitySetterFingerprint, - VideoQualitySettingsParentFingerprint + VideoQualitySetterFingerprint ) ) { override fun execute(context: BytecodeContext) { @@ -62,63 +57,26 @@ class VideoQualityPatch : BytecodePatch( addInstruction( index + 1, - "invoke-static {v$register}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQualityInNewFlyoutPanels(I)V" + "invoke-static {v$register}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V" ) } } } ?: throw NewFlyoutPanelOnClickListenerFingerprint.exception - VideoQualitySetterFingerprint.result?.let { parentResult -> - VideoQualityReferenceFingerprint.also { - it.resolve( - context, - parentResult.classDef - ) - }.result?.let { result -> - result.mutableMethod.apply { - qualityFieldReference = - getInstruction(0).reference as FieldReference + VideoQualitySetterFingerprint.result?.let { + val onItemClickMethod = it.mutableClass.methods.find { method -> method.name == "onItemClick" } - qIndexMethodName = context.classes - .single { it.type == qualityFieldReference.type }.methods - .single { it.parameterTypes.first() == "I" }.name - } - } ?: throw VideoQualityReferenceFingerprint.exception + onItemClickMethod?.apply { + val listItemIndexParameter = 3 - VideoUserQualityChangeFingerprint.also { - it.resolve( - context, - parentResult.classDef + addInstruction( + 0, + "invoke-static {p$listItemIndexParameter}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQualityIndex(I)V" ) - }.result?.mutableMethod?.addInstruction( - 0, - "invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V" - ) ?: throw VideoUserQualityChangeFingerprint.exception + } ?: throw PatchException("Failed to find onItemClick method") } ?: throw VideoQualitySetterFingerprint.exception - VideoQualitySettingsParentFingerprint.result?.let { parentResult -> - VideoQualitySettingsFingerprint.also { - it.resolve( - context, - parentResult.classDef - ) - }.result?.mutableMethod?.let { - relayFieldReference = - it.getInstruction(0).reference as FieldReference - } ?: throw VideoQualitySettingsFingerprint.exception - - parentResult.mutableMethod.addInstructions( - 0, """ - iget-object v0, p0, ${parentResult.classDef.type}->${relayFieldReference.name}:${relayFieldReference.type} - iget-object v1, v0, ${relayFieldReference.type}->${qualityFieldReference.name}:${qualityFieldReference.type} - const-string v2, "$qIndexMethodName" - invoke-static {p1, p2, v1, v2}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I - move-result p2 - """ - ) - } ?: throw VideoQualitySettingsParentFingerprint.exception - - VideoIdPatch.onCreateHook(INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR, "newVideoStarted") + VideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") VideoIdWithoutShortsPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") /** @@ -144,10 +102,5 @@ class VideoQualityPatch : BytecodePatch( private companion object { const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = "$VIDEO_PATH/VideoQualityPatch;" - - private lateinit var qIndexMethodName: String - - private lateinit var relayFieldReference: FieldReference - private lateinit var qualityFieldReference: FieldReference } } \ No newline at end of file