diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt new file mode 100644 index 00000000..d16102ae --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.34.36", "17.36.39", "17.38.36", "17.39.35" , "17.40.41", "17.42.35", "17.43.36") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class OpenLinksDirectlyCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt new file mode 100644 index 00000000..e5c497f7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.openlinksdirectly.annotations.OpenLinksDirectlyCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("open-links-directly-primary-fingerprint") +@OpenLinksDirectlyCompatibility +@Version("0.0.1") +object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( + Opcode.CHECK_CAST, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT, + Opcode.CHECK_CAST, + Opcode.SGET + ) +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt new file mode 100644 index 00000000..2dda99b4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.openlinksdirectly.annotations.OpenLinksDirectlyCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("open-links-directly-secondary-fingerprint") +@OpenLinksDirectlyCompatibility +@Version("0.0.1") +object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.RETURN_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST_STRING + ), + strings = listOf("Uri must have an absolute scheme") +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/patch/OpenLinksDirectlyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/patch/OpenLinksDirectlyPatch.kt new file mode 100644 index 00000000..38ad89a3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/patch/OpenLinksDirectlyPatch.kt @@ -0,0 +1,72 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.openlinksdirectly.annotations.OpenLinksDirectlyCompatibility +import app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints.OpenLinksDirectlyFingerprintPrimary +import app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints.OpenLinksDirectlyFingerprintSecondary +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource +import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.formats.Instruction11x +import org.jf.dexlib2.iface.instruction.formats.Instruction35c + +@Patch +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) +@Name("open-links-directly") +@Description("Bypasses redirect links and allows opening links directly.") +@OpenLinksDirectlyCompatibility +@Version("0.0.1") +class OpenLinksDirectlyPatch : BytecodePatch( + listOf( + OpenLinksDirectlyFingerprintPrimary, OpenLinksDirectlyFingerprintSecondary + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_uri_redirect", + StringResource("revanced_uri_redirect_title", "Open links directly"), + true, + StringResource("revanced_uri_redirect_summary_on", "Enabled"), + StringResource("revanced_uri_redirect_summary_off", "Disabled") + ) + ) + + OpenLinksDirectlyFingerprintPrimary.hookUriParser(true) + OpenLinksDirectlyFingerprintSecondary.hookUriParser(false) + + return PatchResultSuccess() + } +} + +fun MethodFingerprint.hookUriParser(isPrimaryFingerprint: Boolean) { + fun getTargetRegister(instruction: Instruction): Int { + if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC + return (instruction as Instruction11x).registerA + } + with(this.result!!) { + val startIndex = scanResult.patternScanResult!!.startIndex + val instruction = method.implementation!!.instructions.elementAt(startIndex + 1) + val insertIndex = if (isPrimaryFingerprint) 1 else 2 + val targetRegister = getTargetRegister(instruction) + + mutableMethod.addInstructions( + startIndex + insertIndex, """ + invoke-static {v$targetRegister}, Lapp/revanced/integrations/patches/OpenLinksDirectlyPatch;->parseRedirectUri(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """ + ) + } +}