diff --git a/src/main/kotlin/app/revanced/patches/Index.kt b/src/main/kotlin/app/revanced/patches/Index.kt index 3d194b467..bcb2c0be0 100644 --- a/src/main/kotlin/app/revanced/patches/Index.kt +++ b/src/main/kotlin/app/revanced/patches/Index.kt @@ -1,17 +1,20 @@ package app.revanced.patches -import app.revanced.patcher.patch.Patch -import app.revanced.patches.ad.HomeAdsPatch -import app.revanced.patches.ad.HomePromoPatch -import app.revanced.patches.ad.VideoAdsPatch -import app.revanced.patches.interaction.EnableSeekbarTappingPatch -import app.revanced.patches.layout.CreateButtonRemoverPatch -import app.revanced.patches.layout.ShortsButtonRemoverPatch -import app.revanced.patches.layout.HideReelsPatch -import app.revanced.patches.layout.MinimizedPlaybackPatch -import app.revanced.patches.layout.OldQualityLayoutPatch -import app.revanced.patches.misc.IntegrationsPatch -import app.revanced.patches.misc.MicroGPatch +import app.revanced.patcher.data.base.Data +import app.revanced.patcher.patch.base.Patch +import app.revanced.patches.music.audio.CodecsUnlockPatch +import app.revanced.patches.music.audio.EnableAudioOnlyPatch +import app.revanced.patches.music.layout.RemoveTasteBuilderPatch +import app.revanced.patches.music.layout.RemoveUpgradeTabPatch +import app.revanced.patches.music.premium.BackgroundPlayPatch +import app.revanced.patches.youtube.ad.HomeAdsPatch +import app.revanced.patches.youtube.ad.HomePromoPatch +import app.revanced.patches.youtube.ad.VideoAdsPatch +import app.revanced.patches.youtube.interaction.EnableSeekbarTappingPatch +import app.revanced.patches.youtube.layout.* +import app.revanced.patches.youtube.misc.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.IntegrationsPatch +import app.revanced.patches.music.misc.MicroGPatch /** * Index contains all the patches. @@ -22,8 +25,9 @@ object Index { * Array of patches. * New patches should be added to the array. */ - val patches: List<() -> Patch> = listOf( + val patches: List<() -> Patch> = listOf( ::IntegrationsPatch, + ::FixLocaleConfigErrorPatch, ::MicroGPatch, ::HomeAdsPatch, ::VideoAdsPatch, @@ -33,6 +37,11 @@ object Index { ::ShortsButtonRemoverPatch, ::HideReelsPatch, ::OldQualityLayoutPatch, - ::EnableSeekbarTappingPatch + ::EnableSeekbarTappingPatch, + ::EnableAudioOnlyPatch, + ::RemoveUpgradeTabPatch, + ::RemoveTasteBuilderPatch, + ::BackgroundPlayPatch, + ::CodecsUnlockPatch ) } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/misc/MicroGPatch.kt b/src/main/kotlin/app/revanced/patches/misc/MicroGPatch.kt deleted file mode 100644 index c5e3baacf..000000000 --- a/src/main/kotlin/app/revanced/patches/misc/MicroGPatch.kt +++ /dev/null @@ -1,598 +0,0 @@ -package app.revanced.patches.misc - -import app.revanced.extensions.startsWithAny -import app.revanced.patcher.PatcherData -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* -import app.revanced.patcher.proxy -import app.revanced.patcher.proxy.mutableTypes.MutableClass -import app.revanced.patcher.signature.MethodMetadata -import app.revanced.patcher.signature.MethodSignature -import app.revanced.patcher.signature.MethodSignatureMetadata -import app.revanced.patcher.signature.PatternScanMethod -import app.revanced.patcher.smali.toInstruction -import app.revanced.patcher.smali.toInstructions -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.MutableMethodImplementation -import org.jf.dexlib2.builder.instruction.BuilderInstruction21c -import org.jf.dexlib2.iface.instruction.formats.Instruction21c -import org.jf.dexlib2.iface.reference.StringReference -import org.jf.dexlib2.immutable.reference.ImmutableStringReference - -private const val BASE_MICROG_PACKAGE_NAME = "com.mgoogle" -private const val BASE_REVANCED_PACKAGE_NAME = "app.revanced.android.youtube" - -private val compatiblePackages = listOf( - PackageMetadata( - "com.google.android.youtube", listOf("17.14.35") - ) -) - -private val metadata = PatchMetadata( - "microg", - "MicroG Patch", - "Patch to allow YouTube ReVanced to run without root and under a different package name.", - compatiblePackages, - "0.0.1" -) - -private val description = "Signature required for ${metadata.name}." - -enum class StringReplaceMode { - REPLACE_WITH_MICROG, REPLACE_WITH_REVANCED, DO_NOT_REPLACE -} - -class MicroGPatch : Patch( - metadata, listOf( - MethodSignature( - MethodSignatureMetadata( - "google-play-sig-check-method", - MethodMetadata("Ldsf;", "d"), - PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. - compatiblePackages, - description, - "0.0.1" - ), "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"), listOf( - Opcode.MOVE_OBJECT_FROM16, - Opcode.CONST_STRING, - Opcode.CONST_STRING, - Opcode.NEW_INSTANCE, - Opcode.MOVE_OBJECT_FROM16, - Opcode.INVOKE_DIRECT, - Opcode.CONST_4, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IF_EQ, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.SGET, - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_WIDE, - Opcode.CONST_WIDE, - Opcode.CONST_STRING, - Opcode.CONST_4, - Opcode.CONST_STRING, - Opcode.CONST_4, - Opcode.CMP_LONG, - Opcode.IF_GEZ, - Opcode.CONST_16, - Opcode.GOTO_16, - Opcode.CONST_STRING, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.GOTO, - Opcode.MOVE_EXCEPTION, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.CONST_4, - Opcode.IGET_OBJECT, - Opcode.IF_EQZ, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.CONST, - Opcode.IF_NE, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.SGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.GOTO, - Opcode.NEW_ARRAY - ), listOf("This should never happen.", "GooglePlayServicesUtil", "Google Play Store signature invalid.") - ), MethodSignature( - MethodSignatureMetadata( - "google-play-service-checker-method", - MethodMetadata("Llpe;", "d"), - PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. - compatiblePackages, - description, - "0.0.1" - ), "V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), listOf( - Opcode.SGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.SGET_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.IF_NEZ, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.THROW, - Opcode.NEW_INSTANCE, - Opcode.CONST_STRING, - Opcode.INVOKE_DIRECT, - Opcode.THROW, - Opcode.RETURN_VOID - ), listOf("Google Play Services not available") - ), MethodSignature( - MethodSignatureMetadata( - "google-play-utility-method", - MethodMetadata("Llpe;", "b"), - PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. - compatiblePackages, - description, - "0.0.1" - ), "I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L"), listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.GOTO, - Opcode.CONST_STRING, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.CONST_4, - Opcode.IF_NEZ, - Opcode.SGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.GOTO, - Opcode.SGET_OBJECT, - Opcode.MONITOR_ENTER, - Opcode.SGET_BOOLEAN, - Opcode.IF_EQZ, - Opcode.MONITOR_EXIT, - Opcode.GOTO, - Opcode.SPUT_BOOLEAN, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IF_NEZ, - Opcode.MONITOR_EXIT, - Opcode.GOTO, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.SPUT, - Opcode.GOTO, - Opcode.MOVE_EXCEPTION, - Opcode.CONST_STRING, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MONITOR_EXIT, - Opcode.SGET, - Opcode.IF_EQZ, - Opcode.CONST, - Opcode.IF_NE, - Opcode.GOTO, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.THROW, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.THROW, - Opcode.MOVE_EXCEPTION, - Opcode.MONITOR_EXIT, - Opcode.THROW, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.CONST_4, - Opcode.IF_NEZ, - Opcode.SGET_OBJECT, - Opcode.IF_NEZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.SPUT_OBJECT, - Opcode.SGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.CONST_4, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.INVOKE_STATIC, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - Opcode.IF_EQZ, - Opcode.CONST_STRING, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.GOTO, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.CONST_16, - Opcode.GOTO_16, - Opcode.CONST_4, - Opcode.CONST_STRING, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.GOTO, - Opcode.IF_EQZ, - Opcode.INVOKE_STATIC, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.GOTO, - Opcode.IF_EQZ, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.AGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.AGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.GOTO, - Opcode.IGET, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.IF_GE, - Opcode.IGET, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.CONST_4, - Opcode.GOTO, - Opcode.IGET_OBJECT, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.GOTO, - Opcode.MOVE_EXCEPTION, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.GOTO, - Opcode.IGET_BOOLEAN, - Opcode.IF_NEZ, - Opcode.CONST_4, - Opcode.GOTO, - Opcode.RETURN, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.RETURN - ), listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms") - ), MethodSignature( - MethodSignatureMetadata( - "google-play-prime-method", - MethodMetadata("Louy;", "e"), - PatternScanMethod.Direct(), - compatiblePackages, - description, - "0.0.1" - ), null, null, null, null, listOf("com.google.android.GoogleCamera", "com.android.vending") - ) - ) -) { - override fun execute(patcherData: PatcherData): PatchResult { - // smali patches - disablePlayServiceChecks() - patcherData.classes.forEach { classDef -> - var proxiedClass: MutableClass? = null - - classDef.methods.forEach methodLoop@{ method -> - val implementation = method.implementation ?: return@methodLoop - - var proxiedImplementation: MutableMethodImplementation? = null - - implementation.instructions.forEachIndexed { i, instruction -> - if (instruction.opcode == Opcode.CONST_STRING) { - val stringValue = ((instruction as Instruction21c).reference as StringReference).string - - val replaceMode = - if (stringValue.startsWith("com.google.android.gms.chimera.container")) // https://github.com/TeamVanced/VancedMicroG/pull/139/file - StringReplaceMode.DO_NOT_REPLACE - else if (stringValue == "com.google" || stringValue.startsWithAny( - "com.google.android.gms.auth.accounts", - "com.google.android.gms.chimera", - "com.google.android.c2dm", - "com.google.android.c2dm", - "com.google.android.gsf", - "com.google.android.c2dm", - "com.google.iid", - "content://com.google.settings" - ) - ) { - StringReplaceMode.REPLACE_WITH_MICROG - } else if (stringValue.startsWithAny( - "com.google.android.youtube.SuggestionsProvider", - "com.google.android.youtube.fileprovider" - ) - ) { - StringReplaceMode.REPLACE_WITH_REVANCED - } else { - StringReplaceMode.DO_NOT_REPLACE - } - - - if (replaceMode != StringReplaceMode.DO_NOT_REPLACE) { - if (proxiedClass == null) { - proxiedClass = patcherData.proxy(classDef).resolve() - } - - if (proxiedImplementation == null) { - proxiedImplementation = - proxiedClass!!.methods.first { - it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes) - }.implementation!! - } - - val newString = - if (replaceMode == StringReplaceMode.REPLACE_WITH_REVANCED) stringValue.replace( - "com.google.android.youtube", BASE_REVANCED_PACKAGE_NAME - ) - else stringValue.replace("com.google", BASE_MICROG_PACKAGE_NAME) - - proxiedImplementation!!.replaceInstruction( - i, BuilderInstruction21c( - Opcode.CONST_STRING, instruction.registerA, ImmutableStringReference(newString) - ) - ) - } - - // TODO: phenotype reference -> microg reference - //if (instruction is ReferenceInstruction) { - // val proxy = patcherData.proxy(classDef).resolve() - // val implementation = proxy.methods.first { it.name == method.name }.implementation!! - // when (instruction.referenceType) { - // ReferenceType.METHOD -> { - // val reference = instruction.reference as MethodReference - // if (!reference.name.startsWith("com.google.android.gms.phenotype")) return@forEachIndexed - - // val modifiedReference = ImmutableMethodReference( - // reference.definingClass.replace("com.google", BASE_MICROG_PACKAGE_NAME), - // reference.name, - // reference.parameterTypes.map { - // it.toString().replace("com.google", BASE_MICROG_PACKAGE_NAME) - // }, - // reference.returnType.replace("com.google", BASE_MICROG_PACKAGE_NAME), - // ); - - // val newInstruction = when (instruction.opcode.format) { - // Format.Format35c -> { - // val instruction35c = instruction as Instruction35c - // BuilderInstruction35c( - // instruction.opcode, - // instruction35c.registerCount, - // instruction35c.registerC, - // instruction35c.registerD, - // instruction35c.registerE, - // instruction35c.registerF, - // instruction35c.registerG, - // modifiedReference - // ) - // } - // Format.Format3rc -> - // BuilderInstruction3rc( - // instruction.opcode, - // ) - // Format.Format45cc -> - // BuilderInstruction45cc( - // instruction.opcode, - // ) - // Format.Format4rcc -> - // BuilderInstruction4rcc( - // instruction.opcode, - // ) - // } - // implementation.replaceInstruction( - // i, - - // ) - // } - // ReferenceType.METHOD_PROTO -> { - - // } - // ReferenceType.TYPE -> { - - // } - // ReferenceType.CALL_SITE -> { - - // } - // ReferenceType.METHOD_HANDLE -> { - - // } - // ReferenceType.FIELD -> { - - // } - // ReferenceType.NONE -> { - - // } - // } - //} - - } - } - } - } - - // replace string back - val implementation = signatures.elementAt(2).result!!.findParentMethod( - MethodSignature( - MethodSignatureMetadata( - "do-not-replace-method", - MethodMetadata("Llpe;", "c"), - PatternScanMethod.Direct(), - compatiblePackages, - description, - "0.0.1" - ), "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), null, listOf("com.google.android.gms") - ) - )!!.method.implementation!! - - implementation.replaceInstruction( - implementation.instructions.indexOfFirst { it.opcode == Opcode.CONST_STRING }, - "const-string v0, \"com.google.android.gms\"".toInstruction() - ) - - // allow GC to clean unused/ replaced immutable class definitions after this call - patcherData.classes.applyProxies() - - // TODO: resource patches - return PatchResultSuccess() - - } - - private fun disablePlayServiceChecks() { - for (i in 0 until signatures.count() - 1) { - val result = signatures.elementAt(i).result!! - val stringInstructions = when (result.immutableMethod.returnType.first()) { - 'L' -> """ - const/4 v0, 0x0 - return-object v0 - """ - 'V' -> "return-void" - 'I' -> """ - const/4 v0, 0x0 - return v0 - """ - else -> throw Exception("This case should never happen.") - } - result.method.implementation!!.addInstructions( - 0, stringInstructions.trimIndent().toInstructions() - ) - } - - val implementation = signatures.last().result!!.method.implementation!! - - var register = 2 - val index = implementation.instructions.indexOfFirst { - if (it.opcode != Opcode.CONST_STRING) return@indexOfFirst false - - val instructionString = ((it as Instruction21c).reference as StringReference).string - if (instructionString != "com.google.android.youtube") return@indexOfFirst false - - register = it.registerA - return@indexOfFirst true - } - - implementation.replaceInstruction( - index, "const-string v$register, \"$BASE_REVANCED_PACKAGE_NAME\"".toInstruction() - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/audio/CodecsUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/music/audio/CodecsUnlockPatch.kt new file mode 100644 index 000000000..03c2264ff --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/audio/CodecsUnlockPatch.kt @@ -0,0 +1,157 @@ +package app.revanced.patches.music.audio + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.data.implementation.toMethodWalker +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val packageMetadata = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +private val patchMetadata = PatchMetadata( + "codecs-unlock", + "Audio codecs unlock patch", + "Enables more audio codecs. Usually results in better audio quality but may depend on song and device.", + packageMetadata, + "0.0.1" +) + +class CodecsUnlockPatch : BytecodePatch( + patchMetadata, + listOf( + MethodSignature( + MethodSignatureMetadata( + "codec-lock-method", + MethodMetadata( + "Labwj;", + "a", + ), + PatternScanMethod.Fuzzy(2),// FIXME: Test this threshold and find the best value. + packageMetadata, + "Required signature for ${patchMetadata.name}. Discovered in version 5.03.50.", + "0.0.1" + ), + "L", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L", "L", "L", "L"), + listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.SGET, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_INTERFACE, + Opcode.INVOKE_DIRECT, + Opcode.RETURN_OBJECT + ) + ), + MethodSignature( + MethodSignatureMetadata( + "all-codecs-reference-method", + MethodMetadata( + "Laari;", + "b", + ), + PatternScanMethod.Fuzzy(2),// FIXME: Test this threshold and find the best value. + packageMetadata, + "Required signature for ${patchMetadata.name}. Discovered in version 5.03.50.", + "0.0.1" + ), + "J", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L"), + listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.MOVE_EXCEPTION, + Opcode.INVOKE_SUPER, + Opcode.MOVE_RESULT_WIDE, + Opcode.RETURN_WIDE + ), + listOf("itag") + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + var result = signatures.first().result!! + + val implementation = result.method.implementation!! + + val instructionIndex = result.scanData.startIndex + + result = signatures.last().result!! + val codecMethod = data + .toMethodWalker(result.immutableMethod) + .walk(result.scanData.startIndex) + .getMethod() + + implementation.replaceInstruction( + instructionIndex, + "invoke-static {}, ${codecMethod.definingClass}->${codecMethod.name}()Ljava/util/Set;".toInstruction() + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/audio/EnableAudioOnlyPatch.kt b/src/main/kotlin/app/revanced/patches/music/audio/EnableAudioOnlyPatch.kt new file mode 100644 index 000000000..e1186acb0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/audio/EnableAudioOnlyPatch.kt @@ -0,0 +1,133 @@ +package app.revanced.patches.music.audio + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class EnableAudioOnlyPatch : BytecodePatch( + PatchMetadata( + "audio-only-playback-patch", + "Audio Only Mode Patch", + "Add the option to play music without video.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "audio-only-method-signature", + MethodMetadata("Lgmd;", "c"), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L", "Z"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQ, + Opcode.CONST_4, + Opcode.GOTO, + Opcode.NOP, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IF_EQZ, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.RETURN_VOID + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!!.findParentMethod( + MethodSignature( + MethodSignatureMetadata( + "audio-only-enabler-method", + MethodMetadata("Lgmd;", "d"), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf(), + listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.GOTO, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.RETURN + ) + ) + ) ?: return PatchResultError("Required method for ${metadata.shortName} not found.") + + val implementation = result.method.implementation!! + implementation.replaceInstruction( + implementation.instructions.count() - 1, + "const/4 v0, 0x1".toInstruction() + ) + implementation.addInstruction( + "return v0".toInstruction() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/RemoveTasteBuilderPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/RemoveTasteBuilderPatch.kt new file mode 100644 index 000000000..904c16e5d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/RemoveTasteBuilderPatch.kt @@ -0,0 +1,94 @@ +package app.revanced.patches.music.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.formats.Instruction22c + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class RemoveTasteBuilderPatch : BytecodePatch( + PatchMetadata( + "tasteBuilder-remover", + "Remove TasteBuilder Patch", + "Removes the \"Tell us which artists you like\" card from the Home screen. The same functionality can be triggered from the settings anyway.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "taste-builder-constructor", + MethodMetadata("Lkyu;", ""), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Required signature for this patch.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "L", "L", "L"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_VIRTUAL, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + val implementation = result.method.implementation!! + + val insertIndex = result.scanData.endIndex - 8 + + val register = (implementation.instructions[insertIndex] as Instruction22c).registerA + + val instructionList = + """ + const/16 v1, 0x8 + invoke-virtual {v${register}, v1}, Landroid/view/View;->setVisibility(I)V + """.trimIndent().toInstructions().toMutableList() + + implementation.addInstructions( + insertIndex, + instructionList + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/RemoveUpgradeTabPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/RemoveUpgradeTabPatch.kt new file mode 100644 index 000000000..b55c28008 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/RemoveUpgradeTabPatch.kt @@ -0,0 +1,151 @@ +package app.revanced.patches.music.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction22t +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction35c + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class RemoveUpgradeTabPatch : BytecodePatch( + PatchMetadata( + "upgrade-tab-remover", + "Remove Upgrade Tab Patch", + "Remove the upgrade tab from t he pivot bar in YouTube music.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "pivot-bar-constructor", + MethodMetadata("Lhfu;", ""), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Required signature for this patch.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "Z"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.CONST_4, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.GOTO, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.NOP, + Opcode.IPUT_OBJECT, + Opcode.RETURN_VOID + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + val implementation = result.method.implementation!! + + val pivotBarElementFieldRef = + (implementation.instructions[result.scanData.endIndex - 1] as Instruction22c).reference + + val register = (implementation.instructions.first() as Instruction35c).registerC + // first compile all the needed instructions + val instructionList = + """ + invoke-interface { v0 }, Ljava/util/List;->size()I + move-result v1 + const/4 v2, 0x3 + invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object; + iput-object v0, v$register, $pivotBarElementFieldRef + """.trimIndent().toInstructions().toMutableList() + + + // replace the instruction to retain the label at given index + implementation.replaceInstruction( + result.scanData.endIndex - 1, + instructionList[0] // invoke-interface + ) + // do not forget to remove this instruction since we added it already + instructionList.removeFirst() + + val exitInstruction = instructionList.last() // iput-object + implementation.addInstruction( + result.scanData.endIndex, + exitInstruction + ) + // do not forget to remove this instruction since we added it already + instructionList.removeLast() + + // add the necessary if statement to remove the upgrade tab button in case it exists + instructionList.add( + 2, // if-le + BuilderInstruction22t( + Opcode.IF_LE, + 1, 2, + implementation.newLabelForIndex(result.scanData.endIndex) + ) + ) + + implementation.addInstructions( + result.scanData.endIndex, + instructionList + ) + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/premium/BackgroundPlayPatch.kt b/src/main/kotlin/app/revanced/patches/music/premium/BackgroundPlayPatch.kt new file mode 100644 index 000000000..f84aec6fb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/premium/BackgroundPlayPatch.kt @@ -0,0 +1,92 @@ +package app.revanced.patches.music.premium + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class BackgroundPlayPatch : BytecodePatch( + PatchMetadata( + "background-play", + "Enable Background Playback Patch", + "Enable playing music in the background.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "background-playback-disabler-method", + MethodMetadata("Lafgf;", "e"), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "Z", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L"), + listOf( + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET, + Opcode.AND_INT_LIT16, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.GOTO, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_EQZ, + Opcode.CONST_4, + Opcode.RETURN, + Opcode.RETURN, + Opcode.RETURN + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + signatures.first().result!!.method.implementation!!.addInstructions( + 0, + """ + const/4 v0, 0x1 + return v0 + """.trimIndent().toInstructions() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/ad/HomeAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/HomeAdsPatch.kt similarity index 99% rename from src/main/kotlin/app/revanced/patches/ad/HomeAdsPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/ad/HomeAdsPatch.kt index a2158da7f..fda073ee8 100644 --- a/src/main/kotlin/app/revanced/patches/ad/HomeAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/HomeAdsPatch.kt @@ -1,9 +1,13 @@ -package app.revanced.patches.ad +package app.revanced.patches.youtube.ad import app.revanced.extensions.injectHideCall -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -30,7 +34,7 @@ private val patchMetadata = PatchMetadata( private val signatureDescription = "Required signature for ${patchMetadata.name}. Discovered in version 17.03.38." -class HomeAdsPatch : Patch( +class HomeAdsPatch : BytecodePatch( patchMetadata, listOf( MethodSignature( @@ -1685,7 +1689,7 @@ class HomeAdsPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { for (i in 0 until signatures.count()) { val signature = signatures.elementAt(i) val result = signature.result!! diff --git a/src/main/kotlin/app/revanced/patches/ad/HomePromoPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/HomePromoPatch.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/ad/HomePromoPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/ad/HomePromoPatch.kt index a8b6b8854..60cf6105e 100644 --- a/src/main/kotlin/app/revanced/patches/ad/HomePromoPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/HomePromoPatch.kt @@ -1,15 +1,20 @@ -package app.revanced.patches.ad +package app.revanced.patches.youtube.ad import app.revanced.extensions.injectHideCall -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.data.implementation.toMethodWalker import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.proxy.mutableTypes.MutableMethod import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata import app.revanced.patcher.signature.PatternScanMethod -import app.revanced.patcher.toMethodWalker import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.formats.Instruction11x @@ -31,7 +36,7 @@ private val patchMetadata = PatchMetadata( private val signatureDescription = "Required signature for ${patchMetadata.name}. Discovered in version 17.03.38." -class HomePromoPatch : Patch( +class HomePromoPatch : BytecodePatch( patchMetadata, listOf( MethodSignature( @@ -137,7 +142,7 @@ class HomePromoPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { for (signature in signatures) { val result = signature.result!! @@ -162,7 +167,7 @@ class HomePromoPatch : Patch( val toBePatchedInvokeOffset = requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT } - val toBePatchedMethod = patcherData + val toBePatchedMethod = data .toMethodWalker(requiredMethod.immutableMethod) .walk(toBePatchedInvokeOffset, true) .getMethod() as MutableMethod diff --git a/src/main/kotlin/app/revanced/patches/ad/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/VideoAdsPatch.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/ad/VideoAdsPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/ad/VideoAdsPatch.kt index ad8b413e2..4498d3354 100644 --- a/src/main/kotlin/app/revanced/patches/ad/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/VideoAdsPatch.kt @@ -1,9 +1,14 @@ -package app.revanced.patches.ad +package app.revanced.patches.youtube.ad -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -27,7 +32,7 @@ private val patchMetadata = PatchMetadata( "0.0.1" ) -class VideoAdsPatch : Patch( +class VideoAdsPatch : BytecodePatch( patchMetadata, listOf( MethodSignature( @@ -66,7 +71,7 @@ class VideoAdsPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { var result = signatures.first().result!! val responsibleMethodSignature = MethodSignature( @@ -104,5 +109,4 @@ class VideoAdsPatch : Patch( return PatchResultSuccess() } -} - +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/EnableSeekbarTappingPatch.kt similarity index 91% rename from src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTappingPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/interaction/EnableSeekbarTappingPatch.kt index dedf0d4dc..3f49f8309 100644 --- a/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/EnableSeekbarTappingPatch.kt @@ -1,9 +1,14 @@ -package app.revanced.patches.interaction +package app.revanced.patches.youtube.interaction -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -23,7 +28,7 @@ private val compatiblePackages = listOf( ) ) -class EnableSeekbarTappingPatch : Patch( +class EnableSeekbarTappingPatch : BytecodePatch( PatchMetadata( "seekbar-tapping", "Enable seekbar tapping patch", @@ -124,7 +129,7 @@ class EnableSeekbarTappingPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { var result = signatures.first().result!! val tapSeekMethods = mutableMapOf() diff --git a/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/CreateButtonRemoverPatch.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/layout/CreateButtonRemoverPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/CreateButtonRemoverPatch.kt index d945f8e79..4bcde789a 100644 --- a/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/CreateButtonRemoverPatch.kt @@ -1,8 +1,13 @@ -package app.revanced.patches.layout +package app.revanced.patches.youtube.layout -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -19,7 +24,7 @@ private val compatiblePackages = listOf( ) ) -class CreateButtonRemoverPatch : Patch( +class CreateButtonRemoverPatch : BytecodePatch( PatchMetadata( "create-button", "Create button patch", @@ -76,7 +81,7 @@ class CreateButtonRemoverPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { val result = signatures.first().result!! // Get the required register which holds the view object we need to pass to the method hideCreateButton diff --git a/src/main/kotlin/app/revanced/patches/layout/HideReelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/HideReelsPatch.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/layout/HideReelsPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/HideReelsPatch.kt index 7ae117dc8..59fc80e6c 100644 --- a/src/main/kotlin/app/revanced/patches/layout/HideReelsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/HideReelsPatch.kt @@ -1,8 +1,12 @@ -package app.revanced.patches.layout +package app.revanced.patches.youtube.layout -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -18,7 +22,7 @@ private val compatiblePackages = listOf( ) ) -class HideReelsPatch : Patch( +class HideReelsPatch : BytecodePatch( PatchMetadata( "hide-reels", "Hide reels patch", @@ -96,7 +100,7 @@ class HideReelsPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { val result = signatures.first().result!! val implementation = result.method.implementation!! diff --git a/src/main/kotlin/app/revanced/patches/layout/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/MinimizedPlaybackPatch.kt similarity index 81% rename from src/main/kotlin/app/revanced/patches/layout/MinimizedPlaybackPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/MinimizedPlaybackPatch.kt index 0bbf7645f..2383fcfd1 100644 --- a/src/main/kotlin/app/revanced/patches/layout/MinimizedPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/MinimizedPlaybackPatch.kt @@ -1,9 +1,13 @@ -package app.revanced.patches.layout +package app.revanced.patches.youtube.layout -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -19,7 +23,7 @@ private val compatiblePackages = listOf( ) ) -class MinimizedPlaybackPatch : Patch( +class MinimizedPlaybackPatch : BytecodePatch( PatchMetadata( "minimized-playback", "Minimized Playback Patch", @@ -70,7 +74,7 @@ class MinimizedPlaybackPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { // Instead of removing all instructions like Vanced, // we return the method at the beginning instead signatures.first().result!!.method.implementation!!.addInstructions( diff --git a/src/main/kotlin/app/revanced/patches/layout/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/OldQualityLayoutPatch.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/layout/OldQualityLayoutPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/OldQualityLayoutPatch.kt index a69c00718..65eb3744b 100644 --- a/src/main/kotlin/app/revanced/patches/layout/OldQualityLayoutPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/OldQualityLayoutPatch.kt @@ -1,9 +1,14 @@ -package app.revanced.patches.layout +package app.revanced.patches.youtube.layout -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -20,7 +25,7 @@ private val compatiblePackages = listOf( ) ) -class OldQualityLayoutPatch : Patch( +class OldQualityLayoutPatch : BytecodePatch( PatchMetadata( "old-quality-layout", "Old Quality Layout Patch", @@ -70,7 +75,7 @@ class OldQualityLayoutPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { var result = signatures.first().result!! result = result.findParentMethod( diff --git a/src/main/kotlin/app/revanced/patches/layout/ShortsButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/ShortsButtonRemoverPatch.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/layout/ShortsButtonRemoverPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/ShortsButtonRemoverPatch.kt index 318620516..0b0102c66 100644 --- a/src/main/kotlin/app/revanced/patches/layout/ShortsButtonRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/ShortsButtonRemoverPatch.kt @@ -1,8 +1,12 @@ -package app.revanced.patches.layout +package app.revanced.patches.youtube.layout -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignatureMetadata @@ -10,10 +14,7 @@ import app.revanced.patcher.signature.PatternScanMethod import app.revanced.patcher.smali.toInstruction import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.formats.Instruction35c -import org.jf.dexlib2.iface.instruction.formats.Instruction3rc import org.jf.dexlib2.iface.instruction.formats.Instruction11x -import org.jf.dexlib2.builder.instruction.BuilderInstruction32x private val compatiblePackages = listOf( PackageMetadata( @@ -22,7 +23,7 @@ private val compatiblePackages = listOf( ) ) -class ShortsButtonRemoverPatch : Patch( +class ShortsButtonRemoverPatch : BytecodePatch( PatchMetadata( "shorts-button", "Shorts button patch", @@ -105,7 +106,7 @@ class ShortsButtonRemoverPatch : Patch( ), ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { val result1 = signatures.first().result!! val implementation1 = result1.method.implementation!! val moveEnumInstruction = implementation1.instructions[result1.scanData.endIndex] diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/FixLocaleConfigErrorPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/FixLocaleConfigErrorPatch.kt new file mode 100644 index 000000000..77058dbe1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/FixLocaleConfigErrorPatch.kt @@ -0,0 +1,46 @@ +package app.revanced.patches.youtube.misc + +import app.revanced.patcher.data.implementation.ResourceData +import app.revanced.patcher.patch.implementation.ResourcePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import com.sun.org.apache.xerces.internal.dom.ElementImpl + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) +class FixLocaleConfigErrorPatch : ResourcePatch( + PatchMetadata( + "locale-config-fix", + "Manifest attribute fix patch", + "Fix an error when building the resources by patching the manifest file.", + compatiblePackages, + "0.0.1" + ), +) { + override fun execute(data: ResourceData): PatchResult { + // create an xml editor instance + val editor = data.getXmlEditor("AndroidManifest.xml") + + // edit the application nodes attribute... + val applicationNode = editor + .file + .getElementsByTagName("application") + .item(0) as ElementImpl + + // by replacing the attributes name + val attribute = "android:localeConfig" + applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute)) + applicationNode.removeAttribute("android:localeConfig") + + // close & save the modified file + editor.close() + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/misc/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/IntegrationsPatch.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/misc/IntegrationsPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/IntegrationsPatch.kt index 109da2e76..7683f18fb 100644 --- a/src/main/kotlin/app/revanced/patches/misc/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/IntegrationsPatch.kt @@ -1,9 +1,13 @@ -package app.revanced.patches.misc +package app.revanced.patches.youtube.misc -import app.revanced.patcher.PatcherData +import app.revanced.patcher.data.implementation.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.or -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.signature.MethodSignature @@ -22,7 +26,7 @@ private val compatiblePackages = listOf( ) ) -class IntegrationsPatch : Patch( +class IntegrationsPatch : BytecodePatch( PatchMetadata( "integrations", "Inject Integrations Patch", @@ -80,7 +84,7 @@ class IntegrationsPatch : Patch( ) ) ) { - override fun execute(patcherData: PatcherData): PatchResult { + override fun execute(data: BytecodeData): PatchResult { val result = signatures.first().result!! val implementation = result.method.implementation!! diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/MicroGPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/MicroGPatch.kt new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/kotlin/app/revanced/patches/SignatureChecker.kt b/src/test/kotlin/app/revanced/patches/SignatureChecker.kt index 244e4c784..3eda18732 100644 --- a/src/test/kotlin/app/revanced/patches/SignatureChecker.kt +++ b/src/test/kotlin/app/revanced/patches/SignatureChecker.kt @@ -15,7 +15,7 @@ internal class SignatureChecker { if (!file.exists()) { throw IllegalStateException("Missing $file! To run this test, please place stock.apk here: ${file.absolutePath}") } - val patcher = Patcher(file) + val patcher = Patcher(file, "signatureCheckerCache", false) patcher.addPatches(Index.patches.map { it() }) val unresolved = mutableListOf() for (signature in patcher.resolveSignatures()) {