finish batch1

This commit is contained in:
oSumAtrIX
2026-01-11 03:09:35 +01:00
parent a103eb5b7a
commit 32dfe48ad7
38 changed files with 265 additions and 254 deletions

View File

@@ -184,7 +184,6 @@ val spoofBuildInfoPatch = bytecodePatch(
type,
user,
)
},
)
}
)
}

View File

@@ -1,5 +1,10 @@
package app.revanced.patches.googlenews.misc.extension.hooks
import app.revanced.patcher.definingClass
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patches.shared.misc.extension.extensionHook
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -10,32 +15,30 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private var getApplicationContextIndex = -1
internal val startActivityInitHook = extensionHook(
getInsertIndex = { method ->
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
getInsertIndex = {
getApplicationContextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "getApplicationContext"
}
getApplicationContextIndex + 2 // Below the move-result-object instruction.
},
getContextRegister = { method ->
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
as OneRegisterInstruction
getContextRegister = {
val moveResultInstruction = instructions.elementAt(getApplicationContextIndex + 1) as OneRegisterInstruction
"v${moveResultInstruction.registerA}"
},
) {
opcodes(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.IPUT_BOOLEAN,
Opcode.INVOKE_VIRTUAL, // Calls startActivity.getApplicationContext().
Opcode.MOVE_RESULT_OBJECT,
name("onCreate")
definingClass("/StartActivity;"::endsWith)
instructions(
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT(),
Opcode.CONST_4(),
Opcode.IF_EQZ(),
Opcode.CONST(),
Opcode.INVOKE_VIRTUAL(),
Opcode.IPUT_OBJECT(),
Opcode.IPUT_BOOLEAN(),
Opcode.INVOKE_VIRTUAL(), // Calls startActivity.getApplicationContext().
Opcode.MOVE_RESULT_OBJECT(),
)
custom { methodDef, classDef ->
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
}
}

View File

@@ -1,9 +1,11 @@
package app.revanced.patches.googlenews.misc.gms
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
internal val magazinesActivityOnCreateFingerprint = fingerprint {
custom { methodDef, classDef ->
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
}
internal val BytecodePatchContext.magazinesActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("/StartActivity;"::endsWith)
}

View File

@@ -11,7 +11,7 @@ import app.revanced.patches.shared.misc.gms.gmsCoreSupportResourcePatch
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = MAGAZINES_PACKAGE_NAME,
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
getMainActivityOnCreate = magazinesActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = { magazinesActivityOnCreateMethod },
extensionPatch = extensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -1,5 +1,10 @@
package app.revanced.patches.googlephotos.misc.extension
import app.revanced.patcher.definingClass
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patches.shared.misc.extension.extensionHook
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -10,28 +15,26 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private var getApplicationContextIndex = -1
internal val homeActivityInitHook = extensionHook(
getInsertIndex = { method ->
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
getInsertIndex = {
getApplicationContextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "getApplicationContext"
}
getApplicationContextIndex + 2 // Below the move-result-object instruction.
},
getContextRegister = { method ->
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
as OneRegisterInstruction
getContextRegister = {
val moveResultInstruction = instructions.elementAt(getApplicationContextIndex + 1) as OneRegisterInstruction
"v${moveResultInstruction.registerA}"
},
) {
opcodes(
Opcode.CONST_STRING,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.INVOKE_VIRTUAL, // Calls getApplicationContext().
Opcode.MOVE_RESULT_OBJECT,
name("onCreate")
definingClass("/HomeActivity;"::endsWith)
instructions(
Opcode.CONST_STRING(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IF_NEZ(),
Opcode.INVOKE_VIRTUAL(), // Calls getApplicationContext().
Opcode.MOVE_RESULT_OBJECT(),
)
custom { methodDef, classDef ->
methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;")
}
}

View File

@@ -1,9 +1,11 @@
package app.revanced.patches.googlephotos.misc.gms
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
internal val homeActivityOnCreateFingerprint = fingerprint {
custom { methodDef, classDef ->
methodDef.name == "onCreate" && classDef.endsWith("/HomeActivity;")
}
internal val BytecodePatchContext.homeActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("/HomeActivity;"::endsWith)
}

View File

@@ -10,7 +10,7 @@ import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = PHOTOS_PACKAGE_NAME,
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
getMainActivityOnCreate = homeActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = { homeActivityOnCreateMethod },
extensionPatch = extensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -18,5 +18,5 @@ val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameReso
)
},
mainActivityFingerprint = mainActivityOnCreateMethod
getMainActivityMethod = { mainActivityOnCreateMethod }
)

View File

@@ -6,5 +6,6 @@ import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
val sharedExtensionPatch = sharedExtensionPatch(
"music",
applicationInitHook, applicationInitOnCreateHook
applicationInitHook,
applicationInitOnCreateHook
)

View File

@@ -1,18 +1,15 @@
package app.revanced.patches.music.misc.extension.hooks
import app.revanced.patcher.*
import app.revanced.patches.music.shared.YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
import app.revanced.patches.shared.misc.extension.activityOnCreateExtensionHook
import app.revanced.patches.shared.misc.extension.extensionHook
internal val applicationInitHook = extensionHook {
returns("V")
parameters()
instructions(
addString("activity")
)
custom { method, _ -> method.name == "onCreate" }
name("onCreate")
returnType("V")
parameterTypes()
instructions("activity"())
}
internal val applicationInitOnCreateHook = activityOnCreateExtensionHook(
YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
)
internal val applicationInitOnCreateHook = activityOnCreateExtensionHook(YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE)

View File

@@ -8,7 +8,7 @@ fun disableAdsPatch(block: BytecodePatchBuilder.() -> Unit = {}) = bytecodePatch
name = "Disable ads",
) {
apply {
isAdsEnabledFingerprint.method.returnEarly(false)
isAdsEnabledMethod.returnEarly(false)
}
block()

View File

@@ -1,10 +1,12 @@
package app.revanced.patches.reddit.customclients.sync.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val isAdsEnabledFingerprint = fingerprint {
internal val BytecodePatchContext.isAdsEnabledMethod by gettingFirstMutableMethodDeclaratively("SyncIapHelper") {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Z")
strings("SyncIapHelper")
returnType("Z")
}

View File

@@ -1,13 +1,8 @@
package app.revanced.patches.shared.layout.theme
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patcher.patch.*
import app.revanced.util.childElementsSequence
import java.util.Locale
import java.util.*
internal const val THEME_COLOR_OPTION_DESCRIPTION = "Can be a hex color (#RRGGBB) or a color resource reference."
@@ -56,7 +51,8 @@ internal fun validateColorName(colorString: String): Boolean {
* Dark theme color option for YouTube and YT Music Theme patches.
*/
internal val darkThemeBackgroundColorOption = stringOption(
key = "darkThemeBackgroundColor",
name = "Dark theme background color",
description = THEME_COLOR_OPTION_DESCRIPTION,
default = "@android:color/black",
values = mapOf(
"Pure black" to "@android:color/black",
@@ -69,9 +65,7 @@ internal val darkThemeBackgroundColorOption = stringOption(
"Dark yellow" to "#282900",
"Dark orange" to "#291800",
"Dark red" to "#290000",
),
name = "Dark theme background color",
description = THEME_COLOR_OPTION_DESCRIPTION
)
)
/**
@@ -104,10 +98,9 @@ internal fun baseThemeResourcePatch(
lightColorNames: Set<String> = THEME_DEFAULT_LIGHT_COLOR_NAMES,
lightColorReplacement: (() -> String)? = null
) = resourcePatch {
apply {
// After patch option validators are fixed https://github.com/ReVanced/revanced-patcher/issues/372
// This should changed to a patch option validator.
// This should be changed to a patch option validator.
val darkColor by darkThemeBackgroundColorOption
if (!validateColorName(darkColor!!)) {
throw PatchException("Invalid dark theme color: $darkColor")

View File

@@ -1,17 +1,19 @@
package app.revanced.patches.shared.misc.checks
import android.os.Build.*
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import com.android.tools.smali.dexlib2.iface.value.MutableEncodedValue
import com.android.tools.smali.dexlib2.iface.value.MutableLongEncodedValue
import com.android.tools.smali.dexlib2.iface.value.MutableStringEncodedValue
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import com.android.tools.smali.dexlib2.immutable.value.ImmutableLongEncodedValue
import com.android.tools.smali.dexlib2.immutable.value.ImmutableStringEncodedValue
import com.android.tools.smali.dexlib2.mutable.MutableClassDef
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import kotlin.io.encoding.Base64
@@ -21,7 +23,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/checks/CheckEnvironmentPatch;"
fun checkEnvironmentPatch(
mainActivityOnCreateFingerprint: Fingerprint,
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
extensionPatch: Patch,
vararg compatiblePackages: String,
) = bytecodePatch(
@@ -38,20 +40,20 @@ fun checkEnvironmentPatch(
addResources("shared", "misc.checks.checkEnvironmentPatch")
fun setPatchInfo() {
fun <T : MutableEncodedValue> Fingerprint.setClassFields(vararg fieldNameValues: Pair<String, T>) {
fun <T : MutableEncodedValue> MutableClassDef.setClassFields(vararg fieldNameValues: Pair<String, T>) {
val fieldNameValueMap = mapOf(*fieldNameValues)
classDef.fields.forEach { field ->
fields.forEach { field ->
field.initialValue = fieldNameValueMap[field.name] ?: return@forEach
}
}
patchInfoFingerprint.setClassFields(
patchInfoClassDef.setClassFields(
"PATCH_TIME" to System.currentTimeMillis().encoded,
)
fun setBuildInfo() {
patchInfoBuildFingerprint.setClassFields(
patchInfoBuildClassDef.setClassFields(
"PATCH_BOARD" to BOARD.encodedAndHashed,
"PATCH_BOOTLOADER" to BOOTLOADER.encodedAndHashed,
"PATCH_BRAND" to BRAND.encodedAndHashed,
@@ -82,7 +84,7 @@ fun checkEnvironmentPatch(
}
}
fun invokeCheck() = mainActivityOnCreateFingerprint.method.addInstruction(
fun invokeCheck() = getMainActivityOnCreateMethod().addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->check(Landroid/app/Activity;)V",
)

View File

@@ -1,11 +1,12 @@
package app.revanced.patches.shared.misc.checks
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextClassDefMatching.gettingFirstMutableClassDefDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val patchInfoFingerprint = fingerprint {
custom { _, classDef -> classDef.type == "Lapp/revanced/extension/shared/checks/PatchInfo;" }
}
internal val BytecodePatchContext.patchInfoClassDef by gettingFirstMutableClassDefDeclaratively(
"Lapp/revanced/extension/shared/checks/PatchInfo;"
)
internal val patchInfoBuildFingerprint = fingerprint {
custom { _, classDef -> classDef.type == "Lapp/revanced/extension/shared/checks/PatchInfo\$Build;" }
}
internal val BytecodePatchContext.patchInfoBuildClassDef by gettingFirstMutableClassDefDeclaratively(
$$"Lapp/revanced/extension/shared/checks/PatchInfo$Build;"
)

View File

@@ -2,23 +2,16 @@ package app.revanced.patches.shared.misc.debugging
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreference
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.*
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.*
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@@ -45,7 +38,8 @@ internal fun enableDebuggingPatch(
apply {
copyResources(
"settings",
ResourceGroup("drawable",
ResourceGroup(
"drawable",
// Action buttons.
"revanced_settings_copy_all.xml",
"revanced_settings_deselect_all.xml",
@@ -105,9 +99,7 @@ internal fun enableDebuggingPatch(
)
// Hook the methods that look up if a feature flag is active.
experimentalBooleanFeatureFlagFingerprint.match(
experimentalFeatureFlagParentFingerprint.originalClassDef
).method.apply {
experimentalFeatureFlagParentMethod.immutableClassDef.getExperimentalBooleanFeatureFlagMethod().apply {
findInstructionIndicesReversedOrThrow(Opcode.RETURN).forEach { index ->
val register = getInstruction<OneRegisterInstruction>(index).registerA
@@ -121,15 +113,13 @@ internal fun enableDebuggingPatch(
}
}
experimentalDoubleFeatureFlagFingerprint.match(
experimentalFeatureFlagParentFingerprint.originalClassDef
).method.apply {
experimentalFeatureFlagParentMethod.immutableClassDef.getExperimentalDoubleFeatureFlagMethod().apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
addInstructions(
insertIndex,
"""
move-result-wide v0 # Also clobbers v1 (p0) since result is wide.
move-result-wide v0 # Also clobbers v1 (p0) since result is wide.
invoke-static/range { v0 .. v5 }, $EXTENSION_CLASS_DESCRIPTOR->isDoubleFeatureFlagEnabled(DJD)D
move-result-wide v0
return-wide v0
@@ -137,9 +127,7 @@ internal fun enableDebuggingPatch(
)
}
experimentalLongFeatureFlagFingerprint.match(
experimentalFeatureFlagParentFingerprint.originalClassDef
).method.apply {
experimentalFeatureFlagParentMethod.immutableClassDef.getExperimentalLongFeatureFlagMethod().apply {
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.MOVE_RESULT_WIDE)
addInstructions(
@@ -153,21 +141,20 @@ internal fun enableDebuggingPatch(
)
}
if (hookStringFeatureFlag) experimentalStringFeatureFlagFingerprint.match(
experimentalFeatureFlagParentFingerprint.originalClassDef
).method.apply {
val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.MOVE_RESULT_OBJECT)
if (hookStringFeatureFlag)
experimentalFeatureFlagParentMethod.immutableClassDef.getExperimentalStringFeatureFlagMethod().apply {
val insertIndex = indexOfFirstInstructionReversedOrThrow(Opcode.MOVE_RESULT_OBJECT)
addInstructions(
insertIndex,
"""
move-result-object v0
invoke-static { v0, p1, p2, p3 }, $EXTENSION_CLASS_DESCRIPTOR->isStringFeatureFlagEnabled(Ljava/lang/String;JLjava/lang/String;)Ljava/lang/String;
move-result-object v0
return-object v0
"""
)
}
addInstructions(
insertIndex,
"""
move-result-object v0
invoke-static { v0, p1, p2, p3 }, $EXTENSION_CLASS_DESCRIPTOR->isStringFeatureFlagEnabled(Ljava/lang/String;JLjava/lang/String;)Ljava/lang/String;
move-result-object v0
return-object v0
"""
)
}
// There exists other experimental accessor methods for byte[]
// and wrappers for obfuscated classes, but currently none of those are hooked.

View File

@@ -1,35 +1,46 @@
package app.revanced.patches.shared.misc.debugging
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMethodDeclaratively
import app.revanced.patcher.ClassDefMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.ClassDef
internal val experimentalFeatureFlagParentFingerprint = fingerprint {
internal val BytecodePatchContext.experimentalFeatureFlagParentMethod by gettingFirstMethodDeclaratively(
"Unable to parse proto typed experiment flag: "
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("L")
parameters("L", "J", "[B")
strings("Unable to parse proto typed experiment flag: ")
returnType("L")
parameterTypes("L", "J", "[B")
}
internal val experimentalBooleanFeatureFlagFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getExperimentalBooleanFeatureFlagMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Z")
parameters("L", "J", "Z")
returnType("Z")
parameterTypes("L", "J", "Z")
}
internal val experimentalDoubleFeatureFlagFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getExperimentalDoubleFeatureFlagMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("D")
parameters("J", "D")
returnType("D")
parameterTypes("J", "D")
}
internal val experimentalLongFeatureFlagFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getExperimentalLongFeatureFlagMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("J")
parameters("J", "J")
returnType("J")
parameterTypes("J", "J")
}
internal val experimentalStringFeatureFlagFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getExperimentalStringFeatureFlagMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Ljava/lang/String;")
parameters("J", "Ljava/lang/String;")
returnType("Ljava/lang/String;")
parameterTypes("J", "Ljava/lang/String;")
}

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.shared.misc.dns
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import com.android.tools.smali.dexlib2.mutable.MutableMethod
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/patches/CheckWatchHistoryDomainNameResolutionPatch;"
@@ -16,7 +16,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
internal fun checkWatchHistoryDomainNameResolutionPatch(
block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {},
mainActivityFingerprint: Fingerprint
getMainActivityMethod: BytecodePatchContext.() -> MutableMethod
) = bytecodePatch(
name = "Check watch history domain name resolution",
description = "Checks if the device DNS server is preventing user watch history from being saved.",
@@ -28,7 +28,7 @@ internal fun checkWatchHistoryDomainNameResolutionPatch(
addResources("shared", "misc.dns.checkWatchHistoryDomainNameResolutionPatch")
mainActivityFingerprint.method.addInstruction(
getMainActivityMethod().addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->checkDnsResolver(Landroid/app/Activity;)V",
)

View File

@@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patches.all.misc.packagename.changePackageNamePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.spotify.misc.check
import app.revanced.patches.shared.misc.checks.checkEnvironmentPatch
import app.revanced.patches.spotify.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
import app.revanced.patches.spotify.shared.mainActivityOnCreateMethod
internal val checkEnvironmentPatch = checkEnvironmentPatch(
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = { mainActivityOnCreateMethod },
extensionPatch = sharedExtensionPatch,
"com.spotify.music",
)

View File

@@ -2,13 +2,13 @@ package app.revanced.patches.spotify.misc.extension
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patches.shared.misc.extension.extensionHook
import app.revanced.patches.spotify.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.spotify.shared.mainActivityOnCreateMethod
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal val mainActivityOnCreateHook = extensionHook { mainActivityOnCreateFingerprint }
internal val mainActivityOnCreateHook = extensionHook { mainActivityOnCreateMethod }
internal val loadOrbitLibraryHook = extensionHook {
// FIXME: Creating this is a mess and needs refactoring.

View File

@@ -1,15 +1,21 @@
package app.revanced.patches.spotify.shared
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.fingerprint
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;"
internal val mainActivityOnCreateFingerprint = fingerprint {
internal val BytecodePatchContext.mainActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass(SPOTIFY_MAIN_ACTIVITY)
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.type == SPOTIFY_MAIN_ACTIVITY
}
returnType("V")
parameterTypes("Landroid/os/Bundle;")
}

View File

@@ -1,5 +1,8 @@
package app.revanced.patches.tiktok.misc.extension
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patches.shared.misc.extension.activityOnCreateExtensionHook
import app.revanced.patches.shared.misc.extension.extensionHook
@@ -16,19 +19,15 @@ internal val initHook = activityOnCreateExtensionHook(
internal val jatoInitHook = extensionHook(
getContextRegister = { "p1" }
) {
parameters("Landroid/content/Context;")
custom { method, classDef ->
classDef.type == "Lcom/ss/android/ugc/aweme/legoImp/task/JatoInitTask;" &&
method.name == "run"
}
name("run")
definingClass("Lcom/ss/android/ugc/aweme/legoImp/task/JatoInitTask;")
parameterTypes("Landroid/content/Context;")
}
internal val storeRegionInitHook = extensionHook(
getContextRegister = { "p1" }
) {
parameters("Landroid/content/Context;")
custom { method, classDef ->
classDef.type == "Lcom/ss/android/ugc/aweme/legoImp/task/StoreRegionInitTask;" &&
method.name == "run"
}
name("run")
definingClass("Lcom/ss/android/ugc/aweme/legoImp/task/StoreRegionInitTask;")
parameterTypes("Landroid/content/Context;")
}

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.twitter.misc.hook
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.twitter.misc.hook.json.JsonHook
import app.revanced.patches.twitter.misc.hook.json.addJsonHook
import app.revanced.patches.twitter.misc.hook.json.jsonHook
import app.revanced.patches.twitter.misc.hook.json.jsonHookPatch
fun hookPatch(
@@ -19,6 +19,6 @@ fun hookPatch(
)
apply {
addJsonHook(JsonHook(hookClassDescriptor))
addJsonHook(jsonHook(hookClassDescriptor))
}
}

View File

@@ -1,27 +1,29 @@
package app.revanced.patches.twitter.misc.hook.json
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextClassDefMatching.gettingFirstClassDef
import app.revanced.patcher.ClassDefMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
internal val jsonHookPatchFingerprint = fingerprint {
opcodes(
Opcode.INVOKE_INTERFACE, // Add dummy hook to hooks list.
internal val jsonHookPatchMethodMatch = firstMethodComposite {
name("<clinit>")
instructions(
Opcode.INVOKE_INTERFACE(), // Add dummy hook to hooks list.
// Add hooks to the hooks list.
Opcode.INVOKE_STATIC, // Call buildList.
Opcode.INVOKE_STATIC(), // Call buildList.
)
custom { method, _ -> method.name == "<clinit>" }
}
internal val jsonInputStreamFingerprint = fingerprint {
custom { method, _ ->
if (method.parameterTypes.isEmpty()) {
false
} else {
method.parameterTypes.first() == "Ljava/io/InputStream;"
}
context(_: BytecodePatchContext)
internal fun ClassDef.getJsonInputStreamMethod() = firstMutableMethodDeclaratively {
custom {
if (parameterTypes.isEmpty()) false
else parameterTypes.first() == "Ljava/io/InputStream;"
}
}
internal val loganSquareFingerprint = fingerprint {
custom { _, classDef -> classDef.endsWith("LoganSquare;") }
internal val BytecodePatchContext.loganSquareClassDef by gettingFirstClassDef {
type.endsWith("LoganSquare;")
}

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.twitter.misc.hook.json
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstClassDef
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.firstClassDef
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
@@ -15,24 +15,21 @@ import java.io.InvalidClassException
*
* @param jsonHook The [JsonHook] to add.
*/
context(BytecodePatchContext)
fun addJsonHook(
fun BytecodePatchContext.addJsonHook(
jsonHook: JsonHook,
) {
if (jsonHook.added) return
jsonHookPatchFingerprint.method.apply {
// Insert hooks right before calling buildList.
val insertIndex = jsonHookPatchFingerprint.instructionMatches.last().index
// Insert hooks right before calling buildList.
val insertIndex = jsonHookPatchMethodMatch.indices.last()
addInstructions(
insertIndex,
"""
sget-object v1, ${jsonHook.descriptor}->INSTANCE:${jsonHook.descriptor}
invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z
""",
)
}
jsonHookPatchMethodMatch.method.addInstructions(
insertIndex,
"""
sget-object v1, ${jsonHook.descriptor}->INSTANCE:${jsonHook.descriptor}
invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z
""",
)
jsonHook.added = true
}
@@ -48,15 +45,13 @@ val jsonHookPatch = bytecodePatch(
dependsOn(sharedExtensionPatch)
apply {
jsonHookPatchFingerprint.apply {
val jsonHookPatch = firstClassDef(JSON_HOOK_PATCH_CLASS_DESCRIPTOR)
matchOrNull(jsonHookPatch)
jsonHookPatchMethodMatch.apply {
match(firstClassDef(JSON_HOOK_PATCH_CLASS_DESCRIPTOR)).methodOrNull
?: throw PatchException("Unexpected extension.")
}
val jsonFactoryClassDef =
loganSquareFingerprint.originalClassDef // Conveniently find the type to hook a method in, via a named field.
loganSquareClassDef // Conveniently find the type to hook a method in, via a named field.
.fields
.firstOrNull { it.name == "JSON_FACTORY" }
?.type
@@ -64,7 +59,7 @@ val jsonHookPatch = bytecodePatch(
?: throw PatchException("Could not find required class.")
// Hook the methods first parameter.
jsonInputStreamFingerprint.match(jsonFactoryClassDef).method.addInstructions(
jsonFactoryClassDef.getJsonInputStreamMethod().addInstructions(
0,
"""
invoke-static { p1 }, $JSON_HOOK_PATCH_CLASS_DESCRIPTOR->parseJsonHook(Ljava/io/InputStream;)Ljava/io/InputStream;
@@ -75,14 +70,19 @@ val jsonHookPatch = bytecodePatch(
afterDependents {
// Remove hooks.add(dummyHook).
jsonHookPatchFingerprint.method.apply {
val addDummyHookIndex = jsonHookPatchFingerprint.instructionMatches.last().index - 2
val addDummyHookIndex = jsonHookPatchMethodMatch.indices.last()
removeInstructions(addDummyHookIndex, 2)
}
jsonHookPatchMethodMatch.method.removeInstructions(addDummyHookIndex, 2)
}
}
class JsonHook internal constructor(
internal val descriptor: String,
) {
internal var added = false
}
/**
* Create a hook class.
* The class has to extend on **JsonHook**.
@@ -91,22 +91,18 @@ val jsonHookPatch = bytecodePatch(
* @param descriptor The class descriptor of the hook.
* @throws ClassNotFoundException If the class could not be found.
*/
context(BytecodePatchContext)
class JsonHook(
internal val descriptor: String,
) {
internal var added = false
init {
firstClassDef(descriptor).let {
it.also { classDef ->
if (
classDef.superclass != JSON_HOOK_CLASS_DESCRIPTOR ||
!classDef.fields.any { field -> field.name == "INSTANCE" }
) {
throw InvalidClassException(classDef.type, "Not a hook class")
}
context(_: BytecodePatchContext)
fun jsonHook(descriptor: String): JsonHook {
firstClassDef(descriptor).let {
it.also { classDef ->
if (
classDef.superclass != JSON_HOOK_CLASS_DESCRIPTOR ||
!classDef.fields.any { field -> field.name == "INSTANCE" }
) {
throw InvalidClassException(classDef.type, "Not a hook class")
}
}
}
}
return JsonHook(JSON_HOOK_CLASS_DESCRIPTOR)
}

View File

@@ -16,7 +16,7 @@ import app.revanced.patches.youtube.misc.playercontrols.injectVisibilityCheckCal
import app.revanced.patches.youtube.misc.playercontrols.playerControlsPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
import app.revanced.patches.youtube.video.information.videoInformationPatch
import app.revanced.util.ResourceGroup
import app.revanced.util.copyResources
@@ -85,7 +85,7 @@ val downloadsPatch = bytecodePatch(
injectVisibilityCheckCall(BUTTON_DESCRIPTOR)
// Main activity is used to launch downloader intent.
mainActivityOnCreateFingerprint.method.addInstruction(
mainActivityOnCreateMethod.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, ${EXTENSION_CLASS_DESCRIPTOR}->setMainActivity(Landroid/app/Activity;)V"
)

View File

@@ -5,7 +5,6 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_MAIN_ACTIVITY_NAME
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
@Suppress("unused")
val customBrandingPatch = baseCustomBrandingPatch(

View File

@@ -14,10 +14,9 @@ import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_49_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_30_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_34_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.insertLiteralOverride
@@ -155,7 +154,7 @@ val seekbarColorPatch = bytecodePatch(
}
// Hook the splash animation to set the a seekbar color.
mainActivityOnCreateFingerprint.method.apply {
mainActivityOnCreateMethod.method.apply {
val setAnimationIntMethodName =
lottieAnimationViewSetAnimationIntFingerprint.originalMethod.name

View File

@@ -15,7 +15,7 @@ import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -65,7 +65,7 @@ val shortsAutoplayPatch = bytecodePatch(
}
// Main activity is used to check if app is in pip mode.
mainActivityOnCreateFingerprint.method.addInstruction(
mainActivityOnCreateMethod.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->setMainActivity(Landroid/app/Activity;)V",
)

View File

@@ -17,7 +17,7 @@ import app.revanced.patches.youtube.misc.playservice.is_20_39_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -61,7 +61,7 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
)
// Activity is used as the context to launch an Intent.
mainActivityOnCreateFingerprint.method.addInstruction(
mainActivityOnCreateMethod.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setMainActivity(Landroid/app/Activity;)V",

View File

@@ -7,7 +7,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/announcements/AnnouncementsPatch;"
@@ -37,7 +37,7 @@ val announcementsPatch = bytecodePatch(
SwitchPreference("revanced_announcements"),
)
mainActivityOnCreateFingerprint.method.addInstruction(
mainActivityOnCreateMethod.method.addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->showAnnouncement(Landroid/app/Activity;)V",
)

View File

@@ -2,10 +2,10 @@ package app.revanced.patches.youtube.misc.check
import app.revanced.patches.shared.misc.checks.checkEnvironmentPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
internal val checkEnvironmentPatch = checkEnvironmentPatch(
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = { mainActivityOnCreateMethod },
extensionPatch = sharedExtensionPatch,
"com.google.android.youtube",
)

View File

@@ -2,7 +2,6 @@ package app.revanced.patches.youtube.misc.dns
import app.revanced.patches.shared.misc.dns.checkWatchHistoryDomainNameResolutionPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameResolutionPatch(
block = {
@@ -19,5 +18,5 @@ val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameReso
)
)
},
mainActivityFingerprint = mainActivityOnCreateFingerprint
getMainActivityMethod = mainActivityOnCreateFingerprint
)

View File

@@ -13,7 +13,6 @@ import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
@Suppress("unused")
val gmsCoreSupportPatch = gmsCoreSupportPatch(

View File

@@ -13,7 +13,6 @@ import app.revanced.patches.youtube.misc.playservice.is_20_14_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
extensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;",

View File

@@ -1,5 +1,7 @@
package app.revanced.patches.youtube.shared
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
@@ -8,6 +10,11 @@ import app.revanced.patcher.methodCall
import app.revanced.patcher.newInstance
import app.revanced.patcher.opcode
import app.revanced.patcher.addString
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patches.shared.misc.mapping.ResourceType
import app.revanced.patches.shared.misc.mapping.resourceLiteral
import com.android.tools.smali.dexlib2.AccessFlags
@@ -58,12 +65,11 @@ internal val mainActivityOnBackPressedFingerprint = fingerprint {
}
}
internal val mainActivityOnCreateFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.type == YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE
}
internal val BytecodePatchContext.mainActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass(YOUTUBE_MAIN_ACTIVITY_CLASS_TYPE)
returnType("V")
parameterTypes("Landroid/os/Bundle;")
}
internal val rollingNumberTextViewAnimationUpdateFingerprint = fingerprint {
@@ -87,8 +93,8 @@ internal val rollingNumberTextViewAnimationUpdateFingerprint = fingerprint {
)
custom { _, classDef ->
classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" ||
classDef.superclass ==
"Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;"
classDef.superclass ==
"Lcom/google/android/libraries/youtube/rendering/ui/spec/typography/YouTubeAppCompatTextView;"
}
}
@@ -128,6 +134,10 @@ internal val videoQualityChangedFingerprint = fingerprint {
newInstance("Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;"),
opcode(Opcode.IGET_OBJECT),
opcode(Opcode.CHECK_CAST),
fieldAccess(type = "I", opcode = Opcode.IGET, location = MatchAfterImmediately()), // Video resolution (human readable).
fieldAccess(
type = "I",
opcode = Opcode.IGET,
location = MatchAfterImmediately()
), // Video resolution (human readable).
)
}

View File

@@ -6,7 +6,6 @@ import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
@Suppress("unused")
val forceOriginalAudioPatch = forceOriginalAudioPatch(