fix: breaking changes by revanced-patcher dependency

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
oSumAtrIX 2022-05-18 23:58:54 +02:00
parent 3bceed8359
commit e12e484e37
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
68 changed files with 3692 additions and 3594 deletions

View File

@ -27,6 +27,7 @@ dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
implementation("app.revanced:revanced-patcher:1.+") implementation("app.revanced:revanced-patcher:1.+")
implementation(kotlin("reflect"))
} }
java { java {

View File

@ -1,6 +1,6 @@
package app.revanced.extensions package app.revanced.extensions
import app.revanced.patcher.smali.toInstruction import app.revanced.patcher.util.smali.toInstruction
import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.builder.MutableMethodImplementation
internal fun MutableMethodImplementation.injectHideCall( internal fun MutableMethodImplementation.injectHideCall(

View File

@ -1,44 +0,0 @@
package app.revanced.patches
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.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
/**
* Index contains all the patches.
*/
@Suppress("Unused")
object Index {
/**
* Array of patches.
* New patches should be added to the array.
*/
val patches: List<() -> Patch<Data>> = listOf(
::IntegrationsPatch,
::FixLocaleConfigErrorPatch,
//::HomeAdsPatch,
::VideoAdsPatch,
::HomePromoPatch,
::MinimizedPlaybackPatch,
::CreateButtonRemoverPatch,
::ShortsButtonRemoverPatch,
::HideReelsPatch,
::OldQualityLayoutPatch,
::EnableSeekbarTappingPatch,
::EnableAudioOnlyPatch,
::RemoveUpgradeTabPatch,
::RemoveTasteBuilderPatch,
::BackgroundPlayPatch,
::CodecsUnlockPatch
)
}

View File

@ -1,157 +0,0 @@
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()
}
}

View File

@ -1,133 +0,0 @@
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()
}
}

View File

@ -0,0 +1,14 @@
package app.revanced.patches.music.audio.codecs.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class CodecsUnlockCompatibility

View File

@ -0,0 +1,44 @@
package app.revanced.patches.music.audio.codecs.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.data.implementation.toMethodWalker
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
import app.revanced.patches.music.audio.codecs.signatures.AllCodecsReferenceSignature
import app.revanced.patches.music.audio.codecs.signatures.CodecsLockSignature
@Patch
@Name("codecs-unlock")
@Description("Enables more audio codecs. Usually results in better audio quality but may depend on song and device.")
@CodecsUnlockCompatibility
@Version("0.0.1")
class CodecsUnlockPatch : BytecodePatch(
listOf(
CodecsLockSignature, AllCodecsReferenceSignature
)
) {
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()
}
}

View File

@ -0,0 +1,62 @@
package app.revanced.patches.music.audio.codecs.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("all-codecs-reference-signature")
@MatchingMethod(
"Laari;",
"b",
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@CodecsUnlockCompatibility
@Version("0.0.1")
object AllCodecsReferenceSignature : MethodSignature(
"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")
)

View File

@ -0,0 +1,47 @@
package app.revanced.patches.music.audio.codecs.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("codec-lock-signature")
@MatchingMethod(
"Labwj;",
"a",
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@CodecsUnlockCompatibility
@Version("0.0.1")
object CodecsLockSignature : MethodSignature(
"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
)
)

View File

@ -0,0 +1,14 @@
package app.revanced.patches.music.audio.exclusiveaudio.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class ExclusiveAudioCompatibility

View File

@ -0,0 +1,70 @@
package app.revanced.patches.music.audio.exclusiveaudio.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
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.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
import app.revanced.patches.music.audio.exclusiveaudio.signatures.ExclusiveAudioSignature
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Patch
@Name("exclusive-audio-playback")
@Description("Add the option to play music without video.")
@ExclusiveAudioCompatibility
@Version("0.0.1")
class ExclusiveAudioPatch : BytecodePatch(
listOf(
ExclusiveAudioSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = signatures.first().result!!.findParentMethod(@Name("audio-only-enabler-method") @MatchingMethod(
"Lgmd;",
"d"
) @DirectPatternScanMethod @ExclusiveAudioCompatibility @Version(
"0.0.1"
) object : MethodSignature(
"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 parent method could not be found.")
val implementation = result.method.implementation!!
implementation.replaceInstruction(
implementation.instructions.count() - 1, "const/4 v0, 0x1".toInstruction()
)
implementation.addInstruction(
"return v0".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,60 @@
package app.revanced.patches.music.audio.exclusiveaudio.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("exclusive-audio-signature")
@MatchingMethod(
"Lgmd;", "c"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@ExclusiveAudioCompatibility
@Version("0.0.1")
object ExclusiveAudioSignature : MethodSignature(
"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
)
)

View File

@ -1,94 +0,0 @@
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;", "<init>"),
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()
}
}

View File

@ -1,151 +0,0 @@
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;", "<init2>"), // 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()
}
}

View File

@ -0,0 +1,14 @@
package app.revanced.patches.music.layout.tastebuilder.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class RemoveTasteBuilderCompatibility

View File

@ -0,0 +1,46 @@
package app.revanced.patches.music.layout.tastebuilder.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
import app.revanced.patches.music.layout.tastebuilder.signatures.TasteBuilderConstructorSignature
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@Patch
@Name("tasteBuilder-remover")
@Description("Removes the \"Tell us which artists you like\" card from the Home screen. The same functionality can be triggered from the settings anyway.")
@RemoveTasteBuilderCompatibility
@Version("0.0.1")
class RemoveTasteBuilderPatch : BytecodePatch(
listOf(
TasteBuilderConstructorSignature
)
) {
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()
}
}

View File

@ -0,0 +1,43 @@
package app.revanced.patches.music.layout.tastebuilder.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("taste-builder-constructor")
@MatchingMethod(
"Lkyu;", "<init>"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@RemoveTasteBuilderCompatibility
@Version("0.0.1")
object TasteBuilderConstructorSignature : MethodSignature(
"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
)
)

View File

@ -0,0 +1,14 @@
package app.revanced.patches.music.layout.upgradebutton.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class RemoveUpgradeButtonCompatibility

View File

@ -0,0 +1,76 @@
package app.revanced.patches.music.layout.upgradebutton.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
import app.revanced.patches.music.layout.upgradebutton.signatures.PivotBarConstructorSignature
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
@Patch
@Name("upgrade-button-remover")
@Description("Remove the upgrade tab from t he pivot bar in YouTube music.")
@RemoveUpgradeButtonCompatibility
@Version("0.0.1")
class RemoveUpgradeButtonPatch : BytecodePatch(
listOf(
PivotBarConstructorSignature
)
) {
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()
}
}

View File

@ -0,0 +1,71 @@
package app.revanced.patches.music.layout.upgradebutton.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("pivot-bar-constructor")
@MatchingMethod(
"Lhfu;", "<init2>"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@RemoveUpgradeButtonCompatibility
@Version("0.0.1")
object PivotBarConstructorSignature : MethodSignature(
"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
)
)

View File

@ -1,92 +0,0 @@
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()
}
}

View File

@ -0,0 +1,14 @@
package app.revanced.patches.music.premium.backgroundplay.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music", arrayOf("5.03.50")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class BackgroundPlayCompatibility

View File

@ -0,0 +1,37 @@
package app.revanced.patches.music.premium.backgroundplay.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
import app.revanced.patches.music.premium.backgroundplay.signatures.BackgroundPlaybackDisableSignature
@Patch
@Name("background-play")
@Description("Enable playing music in the background.")
@BackgroundPlayCompatibility
@Version("0.0.1")
class BackgroundPlayPatch : BytecodePatch(
listOf(
BackgroundPlaybackDisableSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
signatures.first().result!!.method.implementation!!.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,52 @@
package app.revanced.patches.music.premium.backgroundplay.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("background-playback-disabler-signature")
@MatchingMethod(
"Lafgf;", "e"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@BackgroundPlayCompatibility
@Version("0.0.1")
object BackgroundPlaybackDisableSignature : MethodSignature(
"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
)
)

File diff suppressed because it is too large Load Diff

View File

@ -1,188 +0,0 @@
package app.revanced.patches.youtube.ad
import app.revanced.extensions.injectHideCall
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.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 org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.03.38", "17.14.35", "17.17.34")
)
)
private val patchMetadata = PatchMetadata(
"home-promo-ads",
"Home Promo Ads Patch",
"Patch to remove promoted ads in YouTube",
compatiblePackages,
"0.0.1"
)
private val signatureDescription = "Required signature for ${patchMetadata.name}. Discovered in version 17.03.38."
class HomePromoPatch : BytecodePatch(
patchMetadata,
listOf(
MethodSignature(
MethodSignatureMetadata(
"promoted-discovery-app-parent-method",
MethodMetadata(
"Ljre;",
"lP",
),
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
signatureDescription,
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC,
listOf("L", "L"),
listOf(
Opcode.INVOKE_DIRECT,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.NEW_ARRAY,
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_GE,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.APUT_OBJECT,
Opcode.ADD_INT_LIT8,
Opcode.GOTO
)
),
MethodSignature(
MethodSignatureMetadata(
"promoted-discovery-action-parent-method",
MethodMetadata(
"Ljqv;",
"lP",
),
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
signatureDescription,
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC,
listOf("L", "L"),
listOf(
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL_RANGE,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_BOOLEAN,
Opcode.CONST_4,
Opcode.XOR_INT_2ADDR,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_DIRECT,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CONST_4,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT
)
)
)
) {
override fun execute(data: BytecodeData): PatchResult {
for (signature in signatures) {
val result = signature.result!!
val methodMetadata = MethodMetadata(signature.metadata.methodMetadata!!.definingClass, "d")
val requiredMethod = result.findParentMethod(
MethodSignature(
MethodSignatureMetadata(
"promoted-discovery-action-method",
methodMetadata,
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
signatureDescription,
"0.0.1"
),
"V",
AccessFlags.PRIVATE or AccessFlags.FINAL,
listOf("Z", "Z"),
null
)
)
?: return PatchResultError("Required parent method ${methodMetadata.name} could not be found in ${methodMetadata.definingClass}")
val toBePatchedInvokeOffset =
requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT }
val toBePatchedMethod = data
.toMethodWalker(requiredMethod.immutableMethod)
.walk(toBePatchedInvokeOffset, true)
.getMethod() as MutableMethod
val implementation = toBePatchedMethod.implementation!!
val invokeVirtualOffset = implementation.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_VIRTUAL }
val moveResultInstruction = implementation.instructions[invokeVirtualOffset + 1]
if (moveResultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT)
return PatchResultError("The toBePatchedInvokeOffset offset was wrong in ${metadata.name}")
val register = (moveResultInstruction as Instruction11x).registerA
implementation.injectHideCall(invokeVirtualOffset + 2, register)
}
return PatchResultSuccess()
}
}

View File

@ -1,112 +0,0 @@
package app.revanced.patches.youtube.ad
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.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.toInstructions
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
private val packageMetadata = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.14.35", "17.17.34")
)
)
private val patchMetadata = PatchMetadata(
"video-ads",
"YouTube Video Ads Patch",
"Patch to remove ads in the YouTube video player.",
packageMetadata,
"0.0.1"
)
class VideoAdsPatch : BytecodePatch(
patchMetadata,
listOf(
MethodSignature(
MethodSignatureMetadata(
"show-video-ads-constructor",
MethodMetadata(
"Laadb",
"<init>",
),
PatternScanMethod.Fuzzy(2),// FIXME: Test this threshold and find the best value.
packageMetadata,
"Required signature for ${patchMetadata.name}. Discovered in version 17.14.35.",
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
listOf("L", "L", "L"),
listOf(
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
null, // either CONST_4 or CONST_16
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID
)
)
)
) {
override fun execute(data: BytecodeData): PatchResult {
var result = signatures.first().result!!
val responsibleMethodSignature = MethodSignature(
MethodSignatureMetadata(
"show-video-ads-method",
MethodMetadata(
"zai",
null // unknown
),
PatternScanMethod.Direct(),
packageMetadata,
"Signature to find the method, which is responsible for showing the video ads. Discovered in version 17.14.35",
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
null
)
result = result.findParentMethod(
responsibleMethodSignature
) ?: return PatchResultError(
"Could not find parent method with signature ${responsibleMethodSignature.metadata.name}"
)
// Override the parameter by calling shouldShowAds and setting the parameter to the result
result.method.implementation!!.addInstructions(
0,
"""
invoke-static { }, Lfi/vanced/libraries/youtube/whitelisting/Whitelist;->shouldShowAds()Z
move-result v1
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,14 @@
package app.revanced.patches.youtube.ad.home.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.03.38", "17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class PromotionsCompatibility

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
package app.revanced.patches.youtube.ad.home.patch
import app.revanced.extensions.injectHideCall
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
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.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
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.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.ad.home.annotation.PromotionsCompatibility
import app.revanced.patches.youtube.ad.home.signatures.PromotedDiscoveryActionParentSignature
import app.revanced.patches.youtube.ad.home.signatures.PromotedDiscoveryAppParentSignature
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
@Patch
@Name("home-promo-ads")
@Description("Patch to remove promoted ads in YouTube.")
@PromotionsCompatibility
@Version("0.0.1")
class PromotionsPatch : BytecodePatch(
listOf(
PromotedDiscoveryAppParentSignature, PromotedDiscoveryActionParentSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
for (signature in signatures) {
val result = signature.result!!
val requiredMethod =
result.findParentMethod(@Name("promotion-ads-signature") @MatchingMethod(name = "d") @DirectPatternScanMethod @PromotionsCompatibility @Version(
"0.0.1"
) object : MethodSignature(
"V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("Z", "Z"), null
) {}) ?: return PatchResultError("Required parent method could not be found.")
val toBePatchedInvokeOffset =
requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT }
val toBePatchedMethod =
data.toMethodWalker(requiredMethod.immutableMethod).walk(toBePatchedInvokeOffset, true)
.getMethod() as MutableMethod
val implementation = toBePatchedMethod.implementation!!
val invokeVirtualOffset = implementation.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_VIRTUAL }
val moveResultInstruction = implementation.instructions[invokeVirtualOffset + 1]
if (moveResultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return PatchResultError("The toBePatchedInvokeOffset offset was wrong in ${(this::class.annotations.find { it is Name } as Name).name}")
val register = (moveResultInstruction as Instruction11x).registerA
implementation.injectHideCall(invokeVirtualOffset + 2, register)
}
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,58 @@
package app.revanced.patches.youtube.ad.home.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("promoted-discovery-app-parent-signature")
@MatchingMethod(
"Ljre;", "lP"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@SeekbarTappingCompatibility
@Version("0.0.1")
object PromotedDiscoveryActionParentSignature : MethodSignature(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC,
listOf("L", "L"),
listOf(
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL_RANGE,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_BOOLEAN,
Opcode.CONST_4,
Opcode.XOR_INT_2ADDR,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_DIRECT,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CONST_4,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT
)
)

View File

@ -0,0 +1,61 @@
package app.revanced.patches.youtube.ad.home.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("promoted-discovery-action-parent-signature")
@MatchingMethod(
"Ljqv;",
"lP"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@SeekbarTappingCompatibility
@Version("0.0.1")
object PromotedDiscoveryAppParentSignature : MethodSignature(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC,
listOf("L", "L"),
listOf(
Opcode.INVOKE_DIRECT,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.NEW_ARRAY,
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_GE,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.APUT_OBJECT,
Opcode.ADD_INT_LIT8,
Opcode.GOTO
)
)

View File

@ -0,0 +1,14 @@
package app.revanced.patches.youtube.ad.video.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class VideoAdsCompatibility

View File

@ -0,0 +1,51 @@
package app.revanced.patches.youtube.ad.video.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
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.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
import app.revanced.patches.youtube.ad.video.signatures.ShowVideoAdsConstructorSignature
import org.jf.dexlib2.AccessFlags
@Patch
@Name("video-ads")
@Description("Patch to remove ads in the YouTube video player.")
@VideoAdsCompatibility
@Version("0.0.1")
class VideoAdsPatch : BytecodePatch(
listOf(
ShowVideoAdsConstructorSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result =
signatures.first().result!!.findParentMethod(@Name("show-video-ads-method-signature") @MatchingMethod(
definingClass = "zai"
) @DirectPatternScanMethod @VideoAdsCompatibility @Version("0.0.1") object : MethodSignature(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), null
) {}) ?: return PatchResultError("Required parent method could not be found.")
// Override the parameter by calling shouldShowAds and setting the parameter to the result
result.method.implementation!!.addInstructions(
0, """
invoke-static { }, Lfi/vanced/libraries/youtube/whitelisting/Whitelist;->shouldShowAds()Z
move-result v1
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,40 @@
package app.revanced.patches.youtube.ad.video.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("show-video-ads-constructor-signature")
@MatchingMethod(
"Laadb",
"<init>",
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@SeekbarTappingCompatibility
@Version("0.0.1")
object ShowVideoAdsConstructorSignature : MethodSignature(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
null, // either CONST_4 or CONST_16
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID
)
)

View File

@ -1,186 +0,0 @@
package app.revanced.patches.youtube.interaction
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.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.toInstructions
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.formats.Instruction11n
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.17.34")
)
)
class EnableSeekbarTappingPatch : BytecodePatch(
PatchMetadata(
"seekbar-tapping",
"Enable seekbar tapping patch",
"Enable tapping on the seekbar of the YouTube player.",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"enable-seekbar-tapping-parent-signature",
MethodMetadata("Lzhj;", "J"), // unknown
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
"Signature for a parent method, which is needed to find the actual method required to be patched.",
"0.0.1"
),
"L",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf(),
listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.NEW_ARRAY,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
)
),
MethodSignature(
MethodSignatureMetadata(
"enable-seekbar-tapping-signature",
MethodMetadata("Lfao;", "onTouchEvent"), // unknown
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("L"),
listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.IGET,
Opcode.IGET_OBJECT,
Opcode.IGET,
Opcode.DIV_INT_2ADDR,
Opcode.ADD_INT,
Opcode.SUB_INT_2ADDR,
Opcode.INT_TO_FLOAT,
Opcode.CMPG_FLOAT,
Opcode.IF_GTZ,
Opcode.INT_TO_FLOAT,
Opcode.CMPG_FLOAT,
Opcode.IF_GTZ,
Opcode.CONST_4,
Opcode.INVOKE_INTERFACE,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL
)
)
)
) {
override fun execute(data: BytecodeData): PatchResult {
var result = signatures.first().result!!
val tapSeekMethods = mutableMapOf<String, Method>()
// find the methods which tap the seekbar
for (it in result.definingClassProxy.immutableClass.methods) {
if (it.implementation == null) continue
val instructions = it.implementation!!.instructions
// here we make sure we actually find the method because it has more then 7 instructions
if (instructions.count() < 7) continue
// we know that the 7th instruction has the opcode CONST_4
val instruction = instructions.elementAt(6)
if (instruction.opcode != Opcode.CONST_4) continue
// the literal for this instruction has to be either 1 or 2
val literal = (instruction as Instruction11n).narrowLiteral
// method founds
if (literal == 1) tapSeekMethods["P"] = it
if (literal == 2) tapSeekMethods["O"] = it
}
// replace map because we dont need the upper one anymore
result = signatures.last().result!!
val implementation = result.method.implementation!!
// if tap-seeking is enabled, do not invoke the two methods below
val pMethod = tapSeekMethods["P"]!!
val oMethod = tapSeekMethods["O"]!!
// get the required register
val instruction = implementation.instructions[result.scanData.endIndex]
if (instruction.opcode != Opcode.INVOKE_VIRTUAL)
return PatchResultError("Could not find the correct register")
val register = (instruction as Instruction35c).registerC
// the instructions are written in reverse order.
implementation.addInstructions(
result.scanData.endIndex + 1,
"""
invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V
invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
""".trimIndent().toInstructions()
)
// if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label
val elseLabel = implementation.newLabelForIndex(result.scanData.endIndex + 1)
implementation.addInstruction(
result.scanData.endIndex + 1,
BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel)
)
implementation.addInstructions(
result.scanData.endIndex + 1,
"""
invoke-static { }, Lfi/razerman/youtube/preferences/BooleanPreferences;->isTapSeekingEnabled()Z
move-result v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,14 @@
package app.revanced.patches.youtube.interaction.seekbar.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class SeekbarTappingCompatibility

View File

@ -0,0 +1,94 @@
package app.revanced.patches.youtube.interaction.seekbar.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
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.util.smali.toInstructions
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingParentSignature
import app.revanced.patches.youtube.interaction.seekbar.signatures.SeekbarTappingSignature
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.formats.Instruction11n
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch
@Name("seekbar-tapping")
@Description("Enable tapping on the seekbar of the YouTube player.")
@SeekbarTappingCompatibility
@Version("0.0.1")
class EnableSeekbarTappingPatch : BytecodePatch(
listOf(
SeekbarTappingParentSignature, SeekbarTappingSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
var result = signatures.first().result!!
val tapSeekMethods = mutableMapOf<String, Method>()
// find the methods which tap the seekbar
for (it in result.definingClassProxy.immutableClass.methods) {
if (it.implementation == null) continue
val instructions = it.implementation!!.instructions
// here we make sure we actually find the method because it has more then 7 instructions
if (instructions.count() < 7) continue
// we know that the 7th instruction has the opcode CONST_4
val instruction = instructions.elementAt(6)
if (instruction.opcode != Opcode.CONST_4) continue
// the literal for this instruction has to be either 1 or 2
val literal = (instruction as Instruction11n).narrowLiteral
// method founds
if (literal == 1) tapSeekMethods["P"] = it
if (literal == 2) tapSeekMethods["O"] = it
}
// replace map because we dont need the upper one anymore
result = signatures.last().result!!
val implementation = result.method.implementation!!
// if tap-seeking is enabled, do not invoke the two methods below
val pMethod = tapSeekMethods["P"]!!
val oMethod = tapSeekMethods["O"]!!
// get the required register
val instruction = implementation.instructions[result.scanData.endIndex]
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return PatchResultError("Could not find the correct register")
val register = (instruction as Instruction35c).registerC
// the instructions are written in reverse order.
implementation.addInstructions(
result.scanData.endIndex + 1, """
invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V
invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
""".trimIndent().toInstructions()
)
// if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label
val elseLabel = implementation.newLabelForIndex(result.scanData.endIndex + 1)
implementation.addInstruction(
result.scanData.endIndex + 1, BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel)
)
implementation.addInstructions(
result.scanData.endIndex + 1, """
invoke-static { }, Lfi/razerman/youtube/preferences/BooleanPreferences;->isTapSeekingEnabled()Z
move-result v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,51 @@
package app.revanced.patches.youtube.interaction.seekbar.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("enable-seekbar-tapping-parent")
@MatchingMethod("Lzhj;", "J")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@SeekbarTappingCompatibility
@Version("0.0.1")
object SeekbarTappingParentSignature : MethodSignature(
"L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.NEW_ARRAY,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
)
)

View File

@ -0,0 +1,41 @@
package app.revanced.patches.youtube.interaction.seekbar.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("enable-seekbar-tapping-signature")
@MatchingMethod("Lfao;", "onTouchEvent")
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@SeekbarTappingCompatibility
@Version("0.0.1")
object SeekbarTappingSignature : MethodSignature(
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.IGET,
Opcode.IGET_OBJECT,
Opcode.IGET,
Opcode.DIV_INT_2ADDR,
Opcode.ADD_INT,
Opcode.SUB_INT_2ADDR,
Opcode.INT_TO_FLOAT,
Opcode.CMPG_FLOAT,
Opcode.IF_GTZ,
Opcode.INT_TO_FLOAT,
Opcode.CMPG_FLOAT,
Opcode.IF_GTZ,
Opcode.CONST_4,
Opcode.INVOKE_INTERFACE,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL
)
)

View File

@ -1,102 +0,0 @@
package app.revanced.patches.youtube.layout
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
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.14.35", "17.17.34")
)
)
class CreateButtonRemoverPatch : BytecodePatch(
PatchMetadata(
"create-button",
"Create button patch",
"Disable the create button.",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"create-button-method",
MethodMetadata("Lkne", "z"), // unknown
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("Z"),
listOf(
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.CONST,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT_RANGE,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
)
)
)
) {
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
val implementation = result.method.implementation!!
val instruction = implementation.instructions[result.scanData.endIndex + 1]
if (instruction.opcode != Opcode.INVOKE_STATIC)
return PatchResultError("Could not find the correct register")
val register = (instruction as Instruction35c).registerC
// Hide the button view via proxy by passing it to the hideCreateButton method
implementation.addInstruction(
result.scanData.endIndex + 1,
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->hideCreateButton(Landroid/view/View;)V".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -1,115 +0,0 @@
package app.revanced.patches.youtube.layout
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.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.youtube",
listOf("17.17.34")
)
)
class HideReelsPatch : BytecodePatch(
PatchMetadata(
"hide-reels",
"Hide reels patch",
"Hide reels on the page.",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"hide-reels-signature",
MethodMetadata("Ljvy", "<init>"), // unknown
PatternScanMethod.Fuzzy(3), // 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.CONSTRUCTOR,
listOf(
"L",
"L",
"L",
"L",
"L",
"L",
"L",
"L",
"L",
"L",
"L",
"[B",
"[B",
"[B",
"[B",
"[B",
"[B"
),
listOf(
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT_FROM16,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT_FROM16,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT_FROM16,
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
)
)
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = signatures.first().result!!
val implementation = result.method.implementation!!
// HideReel will hide the reel view before it is being used,
// so we pass the view to the HideReel method
implementation.addInstruction(
result.scanData.endIndex,
"invoke-static { v2 }, Lfi/razerman/youtube/XAdRemover;->HideReel(Landroid/view/View;)V".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -1,89 +0,0 @@
package app.revanced.patches.youtube.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
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.14.35", "17.17.34")
)
)
class MinimizedPlaybackPatch : BytecodePatch(
PatchMetadata(
"minimized-playback",
"Minimized Playback Patch",
"Enable minimized and background playback.",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"minimized-playback-manager",
MethodMetadata("Lype", "j"), // unknown
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
)
)
)
) {
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(
0,
"""
const/4 v0, 0x1
return v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -1,127 +0,0 @@
package app.revanced.patches.youtube.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.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.toInstructions
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.17.34")
)
)
class OldQualityLayoutPatch : BytecodePatch(
PatchMetadata(
"old-quality-layout",
"Old Quality Layout Patch",
"Enable the original quality flyout menu",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"old-quality-parent-method-signature",
MethodMetadata("Libh", "<init>"), // unknown
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
"Signature to find a parent method required by the Old Quality Layout patch.",
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
listOf("L", "L", "L", "L", "L", "L", "L"),
listOf(
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_BOOLEAN,
Opcode.CONST_4,
Opcode.CONST_4,
Opcode.CONST_4,
)
)
)
) {
override fun execute(data: BytecodeData): PatchResult {
var result = signatures.first().result!!
result = result.findParentMethod(
MethodSignature(
MethodSignatureMetadata(
"old-quality-method-signature",
MethodMetadata("Libh", null), // unknown
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
"Signature to find the method required by the Old Quality Layout patch",
"0.0.1"
),
"L",
AccessFlags.FINAL or AccessFlags.PRIVATE,
listOf("Z"),
listOf(
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.GOTO,
Opcode.IGET_OBJECT,
)
)
) ?: return PatchResultError("Method old-quality-patch-method has not been found")
val implementation = result.method.implementation!!
// if useOldStyleQualitySettings == true, jump over all instructions
val jmpInstruction =
BuilderInstruction21t(
Opcode.IF_NEZ,
0,
implementation.instructions[result.scanData.endIndex].location.labels.first()
)
implementation.addInstruction(5, jmpInstruction)
implementation.addInstructions(
0,
"""
invoke-static { }, Lfi/razerman/youtube/XGlobals;->useOldStyleQualitySettings()Z
move-result v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -1,135 +0,0 @@
package app.revanced.patches.youtube.layout
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.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
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.14.35", "17.17.34")
)
)
class ShortsButtonRemoverPatch : BytecodePatch(
PatchMetadata(
"shorts-button",
"Shorts button patch",
"Hide the shorts button.",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"pivotbar-buttons-method-tabenum",
MethodMetadata("Lkne", "z"), // unknown
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
"Signature for the pivotbar method that creates all button views.",
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC, // SomeEnum.fromValue(tabOrdinal)
Opcode.MOVE_RESULT_OBJECT
)
),
MethodSignature(
MethodSignatureMetadata(
"pivotbar-buttons-method-view",
MethodMetadata("Lkne", "z"), // unknown
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
"Signature for the pivotbar method that creates all button views.",
"0.0.1"
),
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.NEW_INSTANCE, // new StateListDrawable()
Opcode.INVOKE_DIRECT,
Opcode.NEW_ARRAY,
Opcode.CONST,
Opcode.CONST_16,
Opcode.APUT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.MOVE,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_VIRTUAL_RANGE, // pivotBar.getView(drawable, tabName, z, i, map, akebVar, optional)
Opcode.MOVE_RESULT_OBJECT,
)
),
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result1 = signatures.first().result!!
val implementation1 = result1.method.implementation!!
val moveEnumInstruction = implementation1.instructions[result1.scanData.endIndex]
val enumRegister = (moveEnumInstruction as Instruction11x).registerA
val result2 = signatures.last().result!!
val implementation2 = result2.method.implementation!!
val moveViewInstruction = implementation2.instructions[result2.scanData.endIndex]
val viewRegister = (moveViewInstruction as Instruction11x).registerA
// Save the tab enum in XGlobals to avoid smali/register workarounds
implementation1.addInstruction(
result1.scanData.endIndex + 1,
"sput-object v$enumRegister, Lfi/razerman/youtube/XGlobals;->lastPivotTab:Ljava/lang/Enum;".toInstruction()
)
// Hide the button view via proxy by passing it to the hideShortsButton method
// It only hides it if the last tab name is "TAB_SHORTS"
implementation2.addInstruction(
result2.scanData.endIndex + 2,
"invoke-static { v$viewRegister }, Lfi/razerman/youtube/XAdRemover;->hideShortsButton(Landroid/view/View;)V".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.layout.createbutton.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class CreateButtonCompatibility

View File

@ -0,0 +1,46 @@
package app.revanced.patches.youtube.layout.createbutton.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
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.util.smali.toInstruction
import app.revanced.patches.youtube.layout.createbutton.signatures.CreateButtonSignature
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch
@Name("disable-create-button")
@Description("Disable the create button.")
@MinimizedPlaybackCompatibility
@Version("0.0.1")
class CreateButtonRemoverPatch : BytecodePatch(
listOf(
CreateButtonSignature
)
) {
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
val implementation = result.method.implementation!!
val instruction = implementation.instructions[result.scanData.endIndex + 1]
if (instruction.opcode != Opcode.INVOKE_STATIC)
return PatchResultError("Could not find the correct register")
val register = (instruction as Instruction35c).registerC
// Hide the button view via proxy by passing it to the hideCreateButton method
implementation.addInstruction(
result.scanData.endIndex + 1,
"invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->hideCreateButton(Landroid/view/View;)V".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,57 @@
package app.revanced.patches.youtube.layout.createbutton.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.amoled.annotations.AmoledCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("create-button-signature")
@MatchingMethod(
"Lkne", "z"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@AmoledCompatibility
@Version("0.0.1")
object CreateButtonSignature : MethodSignature(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.CONST,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT_RANGE,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
)
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.layout.minimizedplayback.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class MinimizedPlaybackCompatibility

View File

@ -0,0 +1,39 @@
package app.revanced.patches.youtube.layout.minimizedplayback.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.youtube.layout.minimizedplayback.signatures.MinimizedPlaybackManagerSignature
@Patch
@Name("minimized-playback")
@Description("Enable minimized and background playback.")
@MinimizedPlaybackCompatibility
@Version("0.0.1")
class MinimizedPlaybackPatch : BytecodePatch(
listOf(
MinimizedPlaybackManagerSignature
)
) {
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(
0, """
const/4 v0, 0x1
return v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,51 @@
package app.revanced.patches.youtube.layout.minimizedplayback.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("minimized-playback-manager-signature")
@MatchingMethod(
"Lype", "j"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@MinimizedPlaybackCompatibility
@Version("0.0.1")
object MinimizedPlaybackManagerSignature : MethodSignature(
"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
)
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.layout.oldqualitylayout.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class OldQualityLayoutCompatibility

View File

@ -0,0 +1,66 @@
package app.revanced.patches.youtube.layout.oldqualitylayout.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
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.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
import app.revanced.patches.youtube.layout.oldqualitylayout.signatures.OldQualityParentSignature
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
@Patch
@Name("old-quality-layout")
@Description("Enable the original quality flyout menu.")
@OldQualityLayoutCompatibility
@Version("0.0.1")
class OldQualityLayoutPatch : BytecodePatch(
listOf(
OldQualityParentSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = signatures.first().result!!.findParentMethod(@Name("old-quality-signature") @MatchingMethod(
definingClass = "Libh"
) @FuzzyPatternScanMethod(2) @OldQualityLayoutCompatibility @Version("0.0.1") object : MethodSignature(
"L", AccessFlags.FINAL or AccessFlags.PRIVATE, listOf("Z"), listOf(
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.GOTO,
Opcode.IGET_OBJECT,
)
) {}) ?: return PatchResultError("Required parent method could not be found.")
val implementation = result.method.implementation!!
// if useOldStyleQualitySettings == true, jump over all instructions
val jmpInstruction = BuilderInstruction21t(
Opcode.IF_NEZ, 0, implementation.instructions[result.scanData.endIndex].location.labels.first()
)
implementation.addInstruction(5, jmpInstruction)
implementation.addInstructions(
0, """
invoke-static { }, Lfi/razerman/youtube/XGlobals;->useOldStyleQualitySettings()Z
move-result v0
""".trimIndent().toInstructions()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,50 @@
package app.revanced.patches.youtube.layout.oldqualitylayout.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("old-quality-parent-method-signature")
@MatchingMethod(
"Libh", "<init>"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@OldQualityLayoutCompatibility
@Version("0.0.1")
object OldQualityParentSignature : MethodSignature(
"V",
AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
listOf("L", "L", "L", "L", "L", "L", "L"),
listOf(
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET_BOOLEAN,
Opcode.CONST_4,
Opcode.CONST_4,
Opcode.CONST_4,
)
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.layout.reels.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class HideReelsCompatibility

View File

@ -0,0 +1,38 @@
package app.revanced.patches.youtube.layout.reels.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility
import app.revanced.patches.youtube.layout.reels.signatures.HideReelsSignature
@Patch
@Name("hide-reels")
@Description("Hide reels on the page.")
@HideReelsCompatibility
@Version("0.0.1")
class HideReelsPatch : BytecodePatch(
listOf(
HideReelsSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = signatures.first().result!!
val implementation = result.method.implementation!!
// HideReel will hide the reel view before it is being used,
// so we pass the view to the HideReel method
implementation.addInstruction(
result.scanData.endIndex,
"invoke-static { v2 }, Lfi/razerman/youtube/XAdRemover;->HideReel(Landroid/view/View;)V".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,58 @@
package app.revanced.patches.youtube.layout.reels.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("hide-reels-signature")
@MatchingMethod(
"Ljvy", "<init>"
)
@FuzzyPatternScanMethod(3) // FIXME: Test this threshold and find the best value.
@HideReelsCompatibility
@Version("0.0.1")
object HideReelsSignature : MethodSignature(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf(
"L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "[B", "[B", "[B", "[B", "[B", "[B"
), listOf(
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT_FROM16,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT_FROM16,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.MOVE_OBJECT_FROM16,
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
)
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.layout.shorts.button.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class ShortsButtonCompatibility

View File

@ -0,0 +1,53 @@
package app.revanced.patches.youtube.layout.shorts.button.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonTabenumSignature
import app.revanced.patches.youtube.layout.shorts.button.signatures.PivotBarButtonsViewSignature
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
@Patch
@Name("shorts-button")
@Description("Hide the shorts button.")
@ShortsButtonCompatibility
@Version("0.0.1")
class ShortsButtonRemoverPatch : BytecodePatch(
listOf(
PivotBarButtonTabenumSignature, PivotBarButtonsViewSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result1 = signatures.first().result!!
val implementation1 = result1.method.implementation!!
val moveEnumInstruction = implementation1.instructions[result1.scanData.endIndex]
val enumRegister = (moveEnumInstruction as Instruction11x).registerA
val result2 = signatures.last().result!!
val implementation2 = result2.method.implementation!!
val moveViewInstruction = implementation2.instructions[result2.scanData.endIndex]
val viewRegister = (moveViewInstruction as Instruction11x).registerA
// Save the tab enum in XGlobals to avoid smali/register workarounds
implementation1.addInstruction(
result1.scanData.endIndex + 1,
"sput-object v$enumRegister, Lfi/razerman/youtube/XGlobals;->lastPivotTab:Ljava/lang/Enum;".toInstruction()
)
// Hide the button view via proxy by passing it to the hideShortsButton method
// It only hides it if the last tab name is "TAB_SHORTS"
implementation2.addInstruction(
result2.scanData.endIndex + 2,
"invoke-static { v$viewRegister }, Lfi/razerman/youtube/XAdRemover;->hideShortsButton(Landroid/view/View;)V".toInstruction()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,45 @@
package app.revanced.patches.youtube.layout.shorts.button.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("pivotbar-buttons-tabenum-signature")
@MatchingMethod(
"Lkne", "z"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@ShortsButtonCompatibility
@Version("0.0.1")
object PivotBarButtonTabenumSignature : MethodSignature(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC, // SomeEnum.fromValue(tabOrdinal)
Opcode.MOVE_RESULT_OBJECT
)
)

View File

@ -0,0 +1,49 @@
package app.revanced.patches.youtube.layout.shorts.button.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButtonCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("pivotbar-buttons-view-signature")
@MatchingMethod(
"Lkne", "z"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@ShortsButtonCompatibility
@Version("0.0.1")
object PivotBarButtonsViewSignature : MethodSignature(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.NEW_INSTANCE, // new StateListDrawable()
Opcode.INVOKE_DIRECT,
Opcode.NEW_ARRAY,
Opcode.CONST,
Opcode.CONST_16,
Opcode.APUT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.MOVE,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_VIRTUAL_RANGE, // pivotBar.getView(drawable, tabName, z, i, map, akebVar, optional)
Opcode.MOVE_RESULT_OBJECT,
)
)

View File

@ -1,125 +0,0 @@
package app.revanced.patches.youtube.misc
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.proxy.mutableTypes.MutableMethod.Companion.toMutable
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.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
private val compatiblePackages = listOf(
PackageMetadata(
"com.google.android.youtube",
listOf("17.03.38", "17.14.35", "17.17.34")
)
)
class IntegrationsPatch : BytecodePatch(
PatchMetadata(
"integrations",
"Inject Integrations Patch",
"Applies mandatory patches to implement the ReVanced integrations into the application.",
compatiblePackages,
"0.0.1"
),
listOf(
MethodSignature(
MethodSignatureMetadata(
"integrations-patch",
MethodMetadata("Lacnx", "onCreate"),
PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value.
compatiblePackages,
"Inject the integrations into the application with the method of this signature",
"0.0.1"
),
"V",
AccessFlags.PUBLIC.value,
listOf(),
listOf(
Opcode.SGET_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IGET_OBJECT,
Opcode.CONST_STRING,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.CHECK_CAST,
Opcode.MOVE_OBJECT,
Opcode.CHECK_CAST,
Opcode.CONST_4,
Opcode.CONST_STRING,
Opcode.INVOKE_INTERFACE_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.SPUT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_SUPER,
Opcode.INVOKE_VIRTUAL
)
)
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = signatures.first().result!!
val implementation = result.method.implementation!!
val count = implementation.registerCount - 1
implementation.addInstructions(
result.scanData.endIndex + 1,
"""
invoke-static {v$count}, Lpl/jakubweg/StringRef;->setContext(Landroid/content/Context;)V
sput-object v$count, Lapp/revanced/integrations/Globals;->context:Landroid/content/Context;
""".trimIndent().toInstructions()
)
val classDef = result.definingClassProxy.resolve()
classDef.methods.add(
ImmutableMethod(
classDef.type,
"getAppContext",
null,
"Landroid/content/Context;",
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
null,
ImmutableMethodImplementation(
1,
"""
invoke-static { }, Lapp/revanced/integrations/Globals;->getAppContext()Landroid/content/Context;
move-result-object v0
return-object v0
""".trimIndent().toInstructions(),
null,
null
)
).toMutable()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.integrations.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.03.38", "17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class IntegrationsCompatibility

View File

@ -0,0 +1,65 @@
package app.revanced.patches.youtube.misc.integrations.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.BytecodePatch
import app.revanced.patcher.patch.implementation.misc.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility
import app.revanced.patches.youtube.misc.integrations.signatures.InitSignature
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
@Patch
@Name("integrations")
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
@IntegrationsCompatibility
@Version("0.0.1")
class IntegrationsPatch : BytecodePatch(
listOf(
InitSignature
)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = signatures.first().result!!
val implementation = result.method.implementation!!
val count = implementation.registerCount - 1
implementation.addInstructions(
result.scanData.endIndex + 1, """
invoke-static {v$count}, Lpl/jakubweg/StringRef;->setContext(Landroid/content/Context;)V
sput-object v$count, Lapp/revanced/integrations/Globals;->context:Landroid/content/Context;
""".trimIndent().toInstructions()
)
val classDef = result.definingClassProxy.resolve()
classDef.methods.add(
ImmutableMethod(
classDef.type,
"getAppContext",
null,
"Landroid/content/Context;",
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
null,
ImmutableMethodImplementation(
1, """
invoke-static { }, Lapp/revanced/integrations/Globals;->getAppContext()Landroid/content/Context;
move-result-object v0
return-object v0
""".trimIndent().toInstructions(), null, null
)
).toMutable()
)
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,57 @@
package app.revanced.patches.youtube.misc.integrations.signatures
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.signature.implementation.method.MethodSignature
import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("init-signature")
@MatchingMethod(
"Lacnx", "onCreate"
)
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
@IntegrationsCompatibility
@Version("0.0.1")
object InitSignature : MethodSignature(
"V",
AccessFlags.PUBLIC.value,
listOf(),
listOf(
Opcode.SGET_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IGET_OBJECT,
Opcode.CONST_STRING,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.CHECK_CAST,
Opcode.MOVE_OBJECT,
Opcode.CHECK_CAST,
Opcode.CONST_4,
Opcode.CONST_STRING,
Opcode.INVOKE_INTERFACE_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.SPUT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_SUPER,
Opcode.INVOKE_VIRTUAL
)
)

View File

@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.manifest.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class FixLocaleConfigErrorCompatibility

View File

@ -1,28 +1,22 @@
package app.revanced.patches.youtube.misc package app.revanced.patches.youtube.misc.manifest.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.implementation.ResourceData import app.revanced.patcher.data.implementation.ResourceData
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.implementation.ResourcePatch 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.PatchResult
import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess
import app.revanced.patches.youtube.misc.manifest.annotations.FixLocaleConfigErrorCompatibility
import org.w3c.dom.Element import org.w3c.dom.Element
private val compatiblePackages = listOf( @Patch
PackageMetadata( @Name("locale-config-fix")
"com.google.android.youtube", @Description("Fix an error when building the resources by patching the manifest file.")
listOf("17.14.35", "17.17.34") @FixLocaleConfigErrorCompatibility
) @Version("0.0.1")
) class FixLocaleConfigErrorPatch : ResourcePatch() {
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 { override fun execute(data: ResourceData): PatchResult {
// create an xml editor instance // create an xml editor instance
val editor = data.getXmlEditor("AndroidManifest.xml") val editor = data.getXmlEditor("AndroidManifest.xml")

View File

@ -1,17 +1,18 @@
package app.revanced.patches package app.revanced.patches
import app.revanced.patcher.Patcher import app.revanced.patcher.Patcher
import app.revanced.patcher.signature.MethodMetadata import app.revanced.patcher.annotation.Name
import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.signature.PatternScanMethod import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod
import app.revanced.patcher.signature.implementation.method.annotation.PatternScanMethod
import org.jf.dexlib2.iface.Method import org.jf.dexlib2.iface.Method
import org.junit.Test import org.junit.Test
import java.io.File import java.io.File
internal class SignatureChecker { internal class SignatureChecker {
@Test @Test
fun checkSignatures() { fun checkMethodSignatures() {
return
// FIXME: instead of having this as a test, it should be turned into a task which can be ran manually // FIXME: instead of having this as a test, it should be turned into a task which can be ran manually
val file = File("stock.apk") val file = File("stock.apk")
if (!file.exists()) { if (!file.exists()) {
@ -19,24 +20,26 @@ internal class SignatureChecker {
} }
val patcher = Patcher(file, "signatureCheckerCache", false) val patcher = Patcher(file, "signatureCheckerCache", false)
patcher.addPatches(Index.patches.map { it() }) patcher.addPatches(Index.patches.map { it() })
val unresolved = mutableListOf<MethodSignature>() val unresolved = mutableListOf<String>()
for (signature in patcher.resolveSignatures()) { for (signature in patcher.resolveSignatures()) {
val signatureAnnotations = signature::class.annotations
val nameAnnotation = signatureAnnotations.find { it is Name } as Name
if (!signature.resolved) { if (!signature.resolved) {
unresolved.add(signature) unresolved.add(nameAnnotation.name)
continue continue
} }
val patternScanMethod = signature.metadata.patternScanMethod val patternScanMethod =
if (patternScanMethod is PatternScanMethod.Fuzzy) { signatureAnnotations.find { it::class.annotations.any { method -> method is PatternScanMethod } }
val warnings = patternScanMethod.warnings!! if (patternScanMethod is FuzzyPatternScanMethod) {
val warnings = signature.result!!.scanData.warnings!!
val method = signature.result!!.method val method = signature.result!!.method
val methodFromMetadata =
if (signature.metadata.methodMetadata != null) signature.metadata.methodMetadata!! else MethodMetadata(
null,
null
)
println("Signature: ${signature.metadata.name}.\nMethod: ${methodFromMetadata.definingClass}->${methodFromMetadata.name} (Signature matches: ${method.definingClass}->${method.toStr()})\nWarnings: ${warnings.count()}") val methodFromMetadata =
signatureAnnotations.find { it is MatchingMethod } as MatchingMethod? ?: MatchingMethod()
println("Signature: ${nameAnnotation}.\nMethod: ${methodFromMetadata.definingClass}->${methodFromMetadata.name} (Signature matches: ${method.definingClass}->${method.toStr()})\nWarnings: ${warnings.count()}")
for (warning in warnings) { for (warning in warnings) {
println("${warning.instructionIndex} / ${warning.patternIndex}: ${warning.wrongOpcode} (expected: ${warning.correctOpcode})") println("${warning.instructionIndex} / ${warning.patternIndex}: ${warning.wrongOpcode} (expected: ${warning.correctOpcode})")
} }
@ -46,8 +49,8 @@ internal class SignatureChecker {
} }
if (unresolved.isNotEmpty()) { if (unresolved.isNotEmpty()) {
val base = Exception("${unresolved.size} signatures were not resolved.") val base = Exception("${unresolved.size} signatures were not resolved.")
for (signature in unresolved) { for (name in unresolved) {
base.addSuppressed(Exception("Signature ${signature.metadata.name} was not resolved!")) base.addSuppressed(Exception("Signature $name was not resolved!"))
} }
throw base throw base
} }