mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-13 05:37:40 +02:00
refactor: move the patch to the correct path
This commit is contained in:
@ -6,6 +6,7 @@ import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultError
|
||||
@ -14,7 +15,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.ambientmode.fingerprints.PowerSaveModeFingerprint
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@ -32,28 +33,30 @@ class PowerSaveModePatch : BytecodePatch(
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
PowerSaveModeFingerprint.result?.mutableMethod?.let { method ->
|
||||
val instructions = method.implementation!!.instructions
|
||||
var powerManagerIndex = -1
|
||||
PowerSaveModeFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
var insertIndex = -1
|
||||
|
||||
for ((index, instruction) in instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) continue
|
||||
for ((index, instruction) in implementation!!.instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) continue
|
||||
|
||||
val invokeInstruction = instruction as Instruction35c
|
||||
if ((invokeInstruction.reference as MethodReference).name != "isPowerSaveMode") continue
|
||||
val invokeInstruction = instruction as Instruction35c
|
||||
if ((invokeInstruction.reference as MethodReference).name != "isPowerSaveMode") continue
|
||||
|
||||
powerManagerIndex = index + 1
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA
|
||||
|
||||
val targetRegister = (instructions.elementAt(powerManagerIndex) as OneRegisterInstruction).registerA
|
||||
insertIndex = index + 2
|
||||
|
||||
method.addInstructions(
|
||||
powerManagerIndex + 1, """
|
||||
invoke-static {v$targetRegister}, $MISC_PATH/PowerSaveModePatch;->bypassPowerSaveModeRestrictions(Z)Z
|
||||
move-result v$targetRegister
|
||||
"""
|
||||
)
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$targetRegister}, $MISC_PATH/PowerSaveModePatch;->bypassPowerSaveModeRestrictions(Z)Z
|
||||
move-result v$targetRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
if (insertIndex == -1)
|
||||
return PatchResultError("Couldn't find PowerManager reference")
|
||||
}
|
||||
if (powerManagerIndex == -1) return PatchResultError("Couldn't find PowerManager reference")
|
||||
} ?: return PowerSaveModeFingerprint.toErrorResult()
|
||||
|
||||
/**
|
||||
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.clientspoof.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
|
||||
parameters = listOf("L", "L", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
),
|
||||
strings = listOf("(Linux; U; Android "),
|
||||
)
|
@ -1,38 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.clientspoof.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.clientspoof.fingerprints.UserAgentHeaderBuilderFingerprint
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
|
||||
@Name("client-spoof")
|
||||
@Description("Spoofs a patched client to allow playback.")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ClientSpoofPatch : BytecodePatch(
|
||||
listOf(UserAgentHeaderBuilderFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
UserAgentHeaderBuilderFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val packageNameRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
|
||||
addInstruction(insertIndex, "const-string v$packageNameRegister, \"$PACKAGE_NAME\"")
|
||||
}
|
||||
} ?: return UserAgentHeaderBuilderFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.externalbrowser.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@ -37,18 +37,20 @@ class ExternalBrowserPatch : BytecodePatch(
|
||||
ExternalBrowserPrimaryFingerprint,
|
||||
ExternalBrowserSecondaryFingerprint,
|
||||
ExternalBrowserTertiaryFingerprint
|
||||
).forEach {
|
||||
val result = it.result?: return it.toErrorResult()
|
||||
it.result?.mutableMethod?.apply {
|
||||
val endIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(endIndex).registerA
|
||||
addInstructions(
|
||||
endIndex + 1, """
|
||||
invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(endIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
endIndex + 1, """
|
||||
invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return fingerprint.toErrorResult()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.fingerprints.LayoutSwitchFingerprint
|
||||
import app.revanced.patches.youtube.misc.forcevp9.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.dexbacked.reference.DexBackedFieldReference
|
||||
@ -128,7 +128,7 @@ class ForceVP9CodecPatch : BytecodePatch(
|
||||
invoke-static {v$register}, $INTEGRATIONS_CLASS_METHOD_REFERENCE
|
||||
move-result v$register
|
||||
return v$register
|
||||
"""
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
@ -136,12 +136,11 @@ class ForceVP9CodecPatch : BytecodePatch(
|
||||
fieldName: String,
|
||||
descriptor: String
|
||||
) {
|
||||
val insertInstructions = implementation!!.instructions
|
||||
val targetString = "Landroid/os/Build;->" +
|
||||
fieldName +
|
||||
":Ljava/lang/String;"
|
||||
|
||||
for ((index, instruction) in insertInstructions.withIndex()) {
|
||||
for ((index, instruction) in implementation!!.instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.SGET_OBJECT) continue
|
||||
|
||||
val indexString = ((instruction as? ReferenceInstruction)?.reference as? DexBackedFieldReference).toString()
|
||||
|
@ -1,7 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.shared.patch.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint
|
||||
|
||||
object InitFingerprint : IntegrationsFingerprint(
|
||||
strings = listOf("Application.onCreate")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.shared.patch.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint
|
||||
|
||||
object ServiceFingerprint : IntegrationsFingerprint(
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("ApiPlayerService;") && it.name == "<init>" },
|
||||
contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size }
|
||||
)
|
@ -1,10 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.shared.patch.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint
|
||||
|
||||
object StandalonePlayerFingerprint : IntegrationsFingerprint(
|
||||
strings = listOf(
|
||||
"Invalid PlaybackStartDescriptor. Returning the instance itself.",
|
||||
"com.google.android.music",
|
||||
),
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.integrations.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.patch.annotations.RequiresIntegrations
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.integrations.AbstractIntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.integrations.fingerprints.*
|
||||
import app.revanced.util.integrations.Constants.INTEGRATIONS_PATH
|
||||
|
||||
@Name("integrations")
|
||||
@YouTubeCompatibility
|
||||
@RequiresIntegrations
|
||||
class IntegrationsPatch : AbstractIntegrationsPatch(
|
||||
"$INTEGRATIONS_PATH/utils/ReVancedUtils;",
|
||||
listOf(InitFingerprint, StandalonePlayerFingerprint, ServiceFingerprint),
|
||||
)
|
@ -18,7 +18,7 @@ import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.fingerprints.LayoutSwitchFingerprint
|
||||
import app.revanced.patches.youtube.misc.layoutswitch.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
|
||||
@Patch
|
||||
|
@ -10,7 +10,7 @@ import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.playertype.patch.PlayerTypeHookPatch
|
||||
|
||||
@DependsOn(
|
||||
[
|
||||
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object CastContextFetchFingerprint : MethodFingerprint(
|
||||
strings = listOf("Error fetching CastContext.")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object CastDynamiteModuleFingerprint : MethodFingerprint(
|
||||
strings = listOf("com.google.android.gms.cast.framework.internal.CastDynamiteModuleImpl")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object CastDynamiteModuleV2Fingerprint : MethodFingerprint(
|
||||
strings = listOf("Failed to load module via V2: ")
|
||||
)
|
@ -1,10 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object GooglePlayUtilityFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
strings = listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints
|
||||
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PrimeFingerprint : MethodFingerprint(
|
||||
strings = listOf("com.google.android.GoogleCamera", "com.android.vending")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object ServiceCheckFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
strings = listOf("Google Play Services not available", "GooglePlayServices not available due to error ")
|
||||
)
|
@ -1,67 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.bytecode.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.packagename.PackageNamePatch
|
||||
import app.revanced.patches.youtube.misc.clientspoof.patch.ClientSpoofPatch
|
||||
import app.revanced.patches.youtube.misc.microg.bytecode.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME
|
||||
import app.revanced.util.bytecode.BytecodeHelper.injectInit
|
||||
import app.revanced.util.microg.MicroGBytecodeHelper
|
||||
|
||||
@Name("microg-support-bytecode-patch")
|
||||
@DependsOn(
|
||||
[
|
||||
ClientSpoofPatch::class,
|
||||
PackageNamePatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class MicroGBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
CastContextFetchFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
PrimeFingerprint,
|
||||
ServiceCheckFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
val packageName = PackageNamePatch.YouTubePackageName!!
|
||||
|
||||
// apply common microG patch
|
||||
MicroGBytecodeHelper.patchBytecode(
|
||||
context, arrayOf(
|
||||
MicroGBytecodeHelper.packageNameTransform(
|
||||
PACKAGE_NAME,
|
||||
packageName
|
||||
)
|
||||
),
|
||||
MicroGBytecodeHelper.PrimeMethodTransformationData(
|
||||
PrimeFingerprint,
|
||||
PACKAGE_NAME,
|
||||
packageName
|
||||
),
|
||||
listOf(
|
||||
ServiceCheckFingerprint,
|
||||
GooglePlayUtilityFingerprint,
|
||||
CastDynamiteModuleFingerprint,
|
||||
CastDynamiteModuleV2Fingerprint,
|
||||
CastContextFetchFingerprint
|
||||
)
|
||||
)
|
||||
|
||||
context.injectInit("MicroGPatch", "checkAvailability")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.packagename.PackageNamePatch
|
||||
import app.revanced.patches.youtube.misc.microg.bytecode.patch.MicroGBytecodePatch
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.SPOOFED_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.misc.microg.shared.Constants.SPOOFED_PACKAGE_SIGNATURE
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.microg.MicroGManifestHelper.addSpoofingMetadata
|
||||
import app.revanced.util.microg.MicroGResourceHelper.patchManifest
|
||||
import app.revanced.util.microg.MicroGResourceHelper.patchSetting
|
||||
import app.revanced.util.resources.ResourceHelper.setMicroG
|
||||
|
||||
@Patch
|
||||
@Name("microg-support")
|
||||
@Description("Allows ReVanced to run without root and under a different package name with MicroG.")
|
||||
@DependsOn(
|
||||
[
|
||||
PackageNamePatch::class,
|
||||
SettingsPatch::class,
|
||||
MicroGBytecodePatch::class,
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class MicroGPatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
val packageName = PackageNamePatch.YouTubePackageName!!
|
||||
|
||||
/*
|
||||
* Add settings
|
||||
*/
|
||||
SettingsPatch.addPreference(
|
||||
arrayOf(
|
||||
"PREFERENCE: MICROG_SETTINGS"
|
||||
)
|
||||
)
|
||||
SettingsPatch.updatePatchStatus("microg-support")
|
||||
|
||||
// update settings fragment
|
||||
context.patchSetting(
|
||||
PACKAGE_NAME,
|
||||
packageName
|
||||
)
|
||||
|
||||
// update manifest
|
||||
context.patchManifest(
|
||||
PACKAGE_NAME,
|
||||
packageName
|
||||
)
|
||||
|
||||
// add metadata to manifest
|
||||
context.addSpoofingMetadata(
|
||||
SPOOFED_PACKAGE_NAME,
|
||||
SPOOFED_PACKAGE_SIGNATURE
|
||||
)
|
||||
|
||||
setMicroG(packageName)
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.microg.shared
|
||||
|
||||
object Constants {
|
||||
internal const val PACKAGE_NAME = "com.google.android.youtube"
|
||||
internal const val SPOOFED_PACKAGE_NAME = PACKAGE_NAME
|
||||
internal const val SPOOFED_PACKAGE_SIGNATURE = "24bb24c05e47e0aefa68a58a766179d9b613a600"
|
||||
}
|
@ -2,7 +2,7 @@ package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.backgroundCategoryId
|
||||
import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch.Companion.BackgroundCategory
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
@ -19,5 +19,5 @@ object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.GOTO
|
||||
),
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(backgroundCategoryId) }
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(BackgroundCategory) }
|
||||
)
|
||||
|
@ -15,10 +15,10 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.utils.playertype.patch.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.reference.MethodReference
|
||||
@ -75,7 +75,7 @@ class MinimizedPlaybackPatch : BytecodePatch(
|
||||
invoke-static {}, $INTEGRATIONS_METHOD_REFERENCE
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
@ -35,16 +35,18 @@ class OpenLinksDirectlyPatch : BytecodePatch(
|
||||
arrayOf(
|
||||
OpenLinksDirectlyFingerprintPrimary,
|
||||
OpenLinksDirectlyFingerprintSecondary
|
||||
).forEach {
|
||||
val result = it.result?: return it.toErrorResult()
|
||||
val insertIndex = result.scanResult.patternScanResult!!.startIndex
|
||||
result.mutableMethod.apply {
|
||||
val register = getInstruction<Instruction35c>(insertIndex).registerC
|
||||
replaceInstruction(
|
||||
insertIndex,
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val register = getInstruction<Instruction35c>(insertIndex).registerC
|
||||
|
||||
replaceInstruction(
|
||||
insertIndex,
|
||||
"invoke-static {v$register}, $MISC_PATH/OpenLinksDirectlyPatch;->enableBypassRedirect(Ljava/lang/String;)Landroid/net/Uri;"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} ?: return fingerprint.toErrorResult()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SpeedClassFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(Opcode.RETURN_OBJECT),
|
||||
strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object VideoSpeedChangedFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL
|
||||
),
|
||||
customFingerprint = { it, _ -> it.name == "onItemClick" }
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object VideoSpeedParentFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("L", "L", "[L", "I"),
|
||||
opcodes = listOf(
|
||||
Opcode.ARRAY_LENGTH,
|
||||
Opcode.IF_GE,
|
||||
Opcode.AGET_OBJECT,
|
||||
Opcode.NEW_INSTANCE
|
||||
)
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object VideoSpeedPatchFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
parameters = listOf("F"),
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("/VideoSpeedPatch;") && it.name == "overrideSpeed"}
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object VideoSpeedSettingsFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("[L", "I"),
|
||||
strings = listOf("menu_item_playback_speed")
|
||||
)
|
@ -1,159 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.toMethodWalker
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.overridespeed.bytecode.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.overridespeed.resource.patch.OverrideSpeedHookResourcePatch
|
||||
import app.revanced.util.integrations.Constants.INTEGRATIONS_PATH
|
||||
import app.revanced.util.integrations.Constants.VIDEO_PATH
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
import org.jf.dexlib2.immutable.*
|
||||
|
||||
@Name("override-speed-hook")
|
||||
@DependsOn([OverrideSpeedHookResourcePatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OverrideSpeedHookPatch : BytecodePatch(
|
||||
listOf(
|
||||
SpeedClassFingerprint,
|
||||
VideoSpeedPatchFingerprint,
|
||||
VideoSpeedParentFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
VideoSpeedParentFingerprint.result?.let { parentResult ->
|
||||
val parentClassDef = parentResult.classDef
|
||||
|
||||
VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
videoSpeedChangedResult = it
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
val reference1 = getInstruction<ReferenceInstruction>(startIndex).reference
|
||||
val reference2 = getInstruction<ReferenceInstruction>(endIndex - 1).reference
|
||||
val reference3 = getInstruction<ReferenceInstruction>(endIndex).reference
|
||||
val fieldReference = reference2 as FieldReference
|
||||
|
||||
val parentMutableClass = parentResult.mutableClass
|
||||
|
||||
parentMutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
parentMutableClass.type,
|
||||
"overrideSpeed",
|
||||
listOf(ImmutableMethodParameter("F", null, null)),
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.PUBLIC,
|
||||
null,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
4, """
|
||||
const/4 v0, 0x0
|
||||
cmpg-float v0, v3, v0
|
||||
if-lez v0, :cond_0
|
||||
iget-object v0, v2, $reference1
|
||||
check-cast v0, ${fieldReference.definingClass}
|
||||
iget-object v1, v0, $reference2
|
||||
invoke-virtual {v1, v3}, $reference3
|
||||
:cond_0
|
||||
return-void
|
||||
""".toInstructions(), null, null
|
||||
)
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
with(context
|
||||
.toMethodWalker(this)
|
||||
.nextMethod(endIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
) {
|
||||
addInstruction(
|
||||
this.implementation!!.instructions.size - 1,
|
||||
"sput p1, $INTEGRATIONS_VIDEO_HELPER_CLASS_DESCRIPTOR->currentSpeed:F"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
} ?: return VideoSpeedChangedFingerprint.toErrorResult()
|
||||
} ?: return VideoSpeedParentFingerprint.toErrorResult()
|
||||
|
||||
|
||||
SpeedClassFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val index = it.scanResult.patternScanResult!!.endIndex
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
SPEED_CLASS = this.returnType
|
||||
replaceInstruction(
|
||||
index,
|
||||
"sput-object v$register, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->speedClass:$SPEED_CLASS"
|
||||
)
|
||||
addInstruction(
|
||||
index + 1,
|
||||
"return-object v$register"
|
||||
)
|
||||
}
|
||||
|
||||
} ?: return SpeedClassFingerprint.toErrorResult()
|
||||
|
||||
VideoSpeedPatchFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
it.mutableClass.staticFields.add(
|
||||
ImmutableField(
|
||||
definingClass,
|
||||
"speedClass",
|
||||
SPEED_CLASS,
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
).toMutable()
|
||||
)
|
||||
|
||||
addInstructions(
|
||||
0, """
|
||||
sget-object v0, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->speedClass:$SPEED_CLASS
|
||||
invoke-virtual {v0, p0}, $SPEED_CLASS->overrideSpeed(F)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
} ?: return VideoSpeedPatchFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
|
||||
"$VIDEO_PATH/VideoSpeedPatch;"
|
||||
|
||||
const val INTEGRATIONS_VIDEO_HELPER_CLASS_DESCRIPTOR =
|
||||
"$INTEGRATIONS_PATH/utils/VideoHelpers;"
|
||||
|
||||
lateinit var videoSpeedChangedResult: MethodFingerprintResult
|
||||
|
||||
private lateinit var SPEED_CLASS: String
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.overridespeed.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.util.resources.ResourceUtils.copyXmlNode
|
||||
|
||||
@Name("override-speed-hook-resource-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class OverrideSpeedHookResourcePatch : ResourcePatch {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
/**
|
||||
* Copy arrays
|
||||
*/
|
||||
context.copyXmlNode("youtube/speed/host", "values/arrays.xml", "resources")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playerbutton.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.liveChatButtonId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object LiveChatFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(Opcode.NEW_INSTANCE),
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(liveChatButtonId) }
|
||||
)
|
@ -1,72 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playerbutton.patch
|
||||
|
||||
import app.revanced.extensions.findMutableMethodOf
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playerbutton.fingerprints.LiveChatFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.util.integrations.Constants.PLAYER
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
|
||||
|
||||
@Name("hook-player-button-patch")
|
||||
@DependsOn([SharedResourceIdPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerButtonPatch : BytecodePatch(
|
||||
listOf(LiveChatFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
LiveChatFingerprint.result?.let {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val instructions = it.mutableMethod.getInstruction(endIndex)
|
||||
val imageButtonClass =
|
||||
context
|
||||
.findClass((instructions as BuilderInstruction21c)
|
||||
.reference.toString())!!
|
||||
.mutableClass
|
||||
|
||||
for (method in imageButtonClass.methods) {
|
||||
with (imageButtonClass.findMutableMethodOf(method)) {
|
||||
var jumpInstruction = true
|
||||
|
||||
implementation!!.instructions.forEachIndexed { index, instructions ->
|
||||
if (instructions.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal) {
|
||||
val definedInstruction = (instructions as? BuilderInstruction35c)
|
||||
|
||||
if (definedInstruction?.reference.toString() ==
|
||||
"Landroid/view/View;->setVisibility(I)V") {
|
||||
|
||||
jumpInstruction = !jumpInstruction
|
||||
if (jumpInstruction) return@forEachIndexed
|
||||
|
||||
val firstRegister = definedInstruction?.registerC
|
||||
val secondRegister = definedInstruction?.registerD
|
||||
|
||||
addInstructions(
|
||||
index, """
|
||||
invoke-static {v$firstRegister, v$secondRegister}, $PLAYER->hidePlayerButton(Landroid/view/View;I)I
|
||||
move-result v$secondRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} ?: return LiveChatFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.bottomUiContainerResourceId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object BottomControlsInflateFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(bottomUiContainerResourceId) }
|
||||
)
|
@ -1,17 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.controlsLayoutStubResourceId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object ControlsLayoutInflateFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(controlsLayoutStubResourceId) }
|
||||
)
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PlayerControlsVisibilityFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("Z", "Z"),
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("YouTubeControlsOverlay;") }
|
||||
)
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object PlayerControlsVisibilityModelFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(Opcode.IGET_BOOLEAN),
|
||||
strings = listOf("hasNext", "hasPrevious", "Missing required properties:")
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||
|
||||
object SeekEDUVisibleFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("Z"),
|
||||
opcodes = listOf(Opcode.OR_INT_LIT8),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.implementation!!.instructions.any {
|
||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 32)
|
||||
}
|
||||
}
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||
|
||||
object UserScrubbingFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("Z"),
|
||||
opcodes = listOf(Opcode.OR_INT_LIT8),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.implementation!!.instructions.any {
|
||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 64)
|
||||
}
|
||||
}
|
||||
)
|
@ -1,96 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playercontrols.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("player-controls-bytecode-patch")
|
||||
@DependsOn([SharedResourceIdPatch::class])
|
||||
@Description("Manages the code for the player controls of the YouTube player.")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerControlsPatch : BytecodePatch(
|
||||
listOf(
|
||||
BottomControlsInflateFingerprint,
|
||||
ControlsLayoutInflateFingerprint,
|
||||
PlayerControlsVisibilityFingerprint,
|
||||
PlayerControlsVisibilityModelFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
val playerControlsVisibilityModelClassDef = PlayerControlsVisibilityModelFingerprint.result?.classDef?: return PlayerControlsVisibilityModelFingerprint.toErrorResult()
|
||||
|
||||
SeekEDUVisibleFingerprint.resolve(context, playerControlsVisibilityModelClassDef)
|
||||
seekEDUVisibleResult = SeekEDUVisibleFingerprint.result?: return SeekEDUVisibleFingerprint.toErrorResult()
|
||||
|
||||
UserScrubbingFingerprint.resolve(context, playerControlsVisibilityModelClassDef)
|
||||
userScrubbingResult = UserScrubbingFingerprint.result?: return UserScrubbingFingerprint.toErrorResult()
|
||||
|
||||
playerControlsVisibilityResult = PlayerControlsVisibilityFingerprint.result?: return PlayerControlsVisibilityFingerprint.toErrorResult()
|
||||
controlsLayoutInflateResult = ControlsLayoutInflateFingerprint.result?: return ControlsLayoutInflateFingerprint.toErrorResult()
|
||||
inflateResult = BottomControlsInflateFingerprint.result?: return BottomControlsInflateFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
lateinit var controlsLayoutInflateResult: MethodFingerprintResult
|
||||
lateinit var inflateResult: MethodFingerprintResult
|
||||
lateinit var playerControlsVisibilityResult: MethodFingerprintResult
|
||||
lateinit var seekEDUVisibleResult: MethodFingerprintResult
|
||||
lateinit var userScrubbingResult: MethodFingerprintResult
|
||||
|
||||
private fun MethodFingerprintResult.injectVisibilityCall(
|
||||
descriptor: String,
|
||||
fieldName: String
|
||||
) {
|
||||
mutableMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static {p1}, $descriptor->$fieldName(Z)V"
|
||||
)
|
||||
}
|
||||
|
||||
private fun MethodFingerprintResult.injectCalls(
|
||||
descriptor: String
|
||||
) {
|
||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||
with (mutableMethod) {
|
||||
val viewRegister = (getInstruction(endIndex) as OneRegisterInstruction).registerA
|
||||
addInstruction(
|
||||
endIndex + 1,
|
||||
"invoke-static {v$viewRegister}, $descriptor->initialize(Ljava/lang/Object;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun injectVisibility(descriptor: String) {
|
||||
playerControlsVisibilityResult.injectVisibilityCall(descriptor, "changeVisibility")
|
||||
seekEDUVisibleResult.injectVisibilityCall(descriptor, "changeVisibilityNegatedImmediate")
|
||||
userScrubbingResult.injectVisibilityCall(descriptor, "changeVisibilityNegatedImmediate")
|
||||
}
|
||||
|
||||
fun initializeSB(descriptor: String) {
|
||||
controlsLayoutInflateResult.injectCalls(descriptor)
|
||||
}
|
||||
|
||||
fun initializeControl(descriptor: String) {
|
||||
inflateResult.injectCalls(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playeroverlay.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint(
|
||||
customFingerprint = { it, _ ->
|
||||
it.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && it.name == "onFinishInflate"
|
||||
}
|
||||
)
|
@ -1,34 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playeroverlay.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint
|
||||
import app.revanced.util.integrations.Constants.UTILS_PATH
|
||||
|
||||
@Name("player-overlays-hook")
|
||||
@Description("Hook for adding custom overlays to the video player.")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerOverlaysHookPatch : BytecodePatch(
|
||||
listOf(PlayerOverlaysOnFinishInflateFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
// hook YouTubePlayerOverlaysLayout.onFinishInflate()
|
||||
PlayerOverlaysOnFinishInflateFingerprint.result?.mutableMethod?.let {
|
||||
it.addInstruction(
|
||||
it.implementation!!.instructions.size - 2,
|
||||
"invoke-static { p0 }, $UTILS_PATH/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V"
|
||||
)
|
||||
} ?: return PlayerOverlaysOnFinishInflateFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playertype.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object UpdatePlayerTypeFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IF_NE,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { it, _ ->
|
||||
it.definingClass.endsWith("YouTubePlayerOverlaysLayout;")
|
||||
}
|
||||
)
|
@ -1,34 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.playertype.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint
|
||||
import app.revanced.util.integrations.Constants.UTILS_PATH
|
||||
|
||||
@Name("player-type-hook")
|
||||
@Description("Hook to get the current player type of WatchWhileActivity")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class PlayerTypeHookPatch : BytecodePatch(
|
||||
listOf(
|
||||
UpdatePlayerTypeFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
// hook YouTubePlayerOverlaysLayout.updatePlayerLayout()
|
||||
UpdatePlayerTypeFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"invoke-static { p1 }, $UTILS_PATH/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V"
|
||||
) ?: return UpdatePlayerTypeFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.protobufpoof.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object BadResponseFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(Opcode.CONST_16),
|
||||
strings = listOf("Response code: ")
|
||||
)
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.protobufpoof.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object ProtobufParameterBuilderFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL_RANGE, // target reference
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IPUT_OBJECT
|
||||
),
|
||||
strings = listOf("Unexpected empty videoId.", "Prefetch request are disabled.")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.protobufpoof.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object SubtitleWindowFingerprint : MethodFingerprint(
|
||||
parameters = listOf("I", "I", "I", "Z", "Z"),
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("SubtitleWindowSettings;") && it.name == "<init>" }
|
||||
)
|
@ -1,100 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.protobufpoof.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.toMethodWalker
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.protobufpoof.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
|
||||
@Patch
|
||||
@Name("protobuf-spoof")
|
||||
@Description("Spoofs the protobuf to prevent playback issues.")
|
||||
@DependsOn(
|
||||
[
|
||||
MainstreamVideoIdPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ProtobufSpoofPatch : BytecodePatch(
|
||||
listOf(
|
||||
BadResponseFingerprint,
|
||||
ProtobufParameterBuilderFingerprint,
|
||||
SubtitleWindowFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
// hook parameter
|
||||
ProtobufParameterBuilderFingerprint.result?.let {
|
||||
(context
|
||||
.toMethodWalker(it.method)
|
||||
.nextMethod(it.scanResult.patternScanResult!!.startIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
).apply {
|
||||
val protobufParam = 3
|
||||
|
||||
addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {p$protobufParam}, $MISC_PATH/ProtobufSpoofPatch;->overrideProtobufParameter(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object p$protobufParam
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return ProtobufParameterBuilderFingerprint.toErrorResult()
|
||||
|
||||
// hook video playback result
|
||||
BadResponseFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"invoke-static {}, $MISC_PATH/ProtobufSpoofPatch;->switchProtobufSpoof()V"
|
||||
) ?: return BadResponseFingerprint.toErrorResult()
|
||||
|
||||
// fix protobuf spoof side issue
|
||||
SubtitleWindowFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {p1, p2, p3, p4, p5}, $MISC_PATH/ProtobufSpoofPatch;->getSubtitleWindowSettingsOverride(IIIZZ)[I
|
||||
move-result-object v0
|
||||
const/4 v1, 0x0
|
||||
aget p1, v0, v1 # ap, anchor position
|
||||
const/4 v1, 0x1
|
||||
aget p2, v0, v1 # ah, horizontal anchor
|
||||
const/4 v1, 0x2
|
||||
aget p3, v0, v1 # av, vertical anchor
|
||||
"""
|
||||
) ?: return SubtitleWindowFingerprint.toErrorResult()
|
||||
|
||||
// Hook video id, required for subtitle fix.
|
||||
MainstreamVideoIdPatch.injectCall("$MISC_PATH/ProtobufSpoofPatch;->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
|
||||
/**
|
||||
* Add settings
|
||||
*/
|
||||
SettingsPatch.addPreference(
|
||||
arrayOf(
|
||||
"SETTINGS: ENABLE_PROTOBUF_SPOOF"
|
||||
)
|
||||
)
|
||||
SettingsPatch.updatePatchStatus("protobuf-spoof")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -7,5 +7,5 @@ object CronetEngineBuilderFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC.value,
|
||||
parameters = listOf("Z"),
|
||||
customFingerprint = { it, _ -> it.definingClass == "Lorg/chromium/net/CronetEngine\$Builder;" && it.name == "enableQuic" }
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("CronetEngine\$Builder;") && it.name == "enableQuic" }
|
||||
)
|
@ -7,5 +7,5 @@ object ExperimentalCronetEngineBuilderFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC.value,
|
||||
parameters = listOf("Z"),
|
||||
customFingerprint = { it, _ -> it.definingClass == "Lorg/chromium/net/ExperimentalCronetEngine\$Builder;" && it.name == "enableQuic" }
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("ExperimentalCronetEngine\$Builder;") && it.name == "enableQuic" }
|
||||
)
|
@ -13,7 +13,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.quic.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
|
||||
@Patch
|
||||
|
@ -1,124 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.resourceid.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
|
||||
import app.revanced.util.enum.ResourceType
|
||||
import app.revanced.util.enum.ResourceType.*
|
||||
|
||||
@Name("shared-resource-id")
|
||||
@DependsOn([ResourceMappingPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class SharedResourceIdPatch : ResourcePatch {
|
||||
internal companion object {
|
||||
var accessibilityProgressTimeId: Long = -1
|
||||
var accountSwitcherAccessibilityId: Long = -1
|
||||
var adAttributionId: Long = -1
|
||||
var appearanceStringId: Long = -1
|
||||
var appRelatedEndScreenResultsId: Long = -1
|
||||
var autoNavPreviewId: Long = -1
|
||||
var backgroundCategoryId: Long = -1
|
||||
var barContainerHeightId: Long = -1
|
||||
var bottomUiContainerResourceId: Long = -1
|
||||
var channelListSubMenuId: Long = -1
|
||||
var chapterRepeatOnResourceId: Long = -1
|
||||
var compactLinkId: Long = -1
|
||||
var controlsLayoutStubResourceId: Long = -1
|
||||
var dislikeButtonId: Long = -1
|
||||
var donationCompanionResourceId: Long = -1
|
||||
var easySeekEduContainerId: Long = -1
|
||||
var expandButtonId: Long = -1
|
||||
var fabId: Long = -1
|
||||
var filterBarHeightId: Long = -1
|
||||
var floatyBarTopMarginId: Long = -1
|
||||
var horizontalCardListId: Long = -1
|
||||
var imageOnlyTabId: Long = -1
|
||||
var inlineTimeBarColorizedBarPlayedColorDarkId: Long = -1
|
||||
var inlineTimeBarPlayedNotHighlightedColorId: Long = -1
|
||||
var insetOverlayViewLayoutId: Long = -1
|
||||
var layoutCircleId: Long = -1
|
||||
var layoutIconId: Long = -1
|
||||
var layoutVideoId: Long = -1
|
||||
var likeButtonId: Long = -1
|
||||
var liveChatButtonId: Long = -1
|
||||
var reelPlayerBadgeId: Long = -1
|
||||
var reelPlayerBadge2Id: Long = -1
|
||||
var reelPlayerFooterId: Long = -1
|
||||
var reelPlayerInfoPanelId: Long = -1
|
||||
var reelPlayerPausedId: Long = -1
|
||||
var reelRemixId: Long = -1
|
||||
var relatedChipCloudMarginId: Long = -1
|
||||
var rightCommentId: Long = -1
|
||||
var scrimOverlayId: Long = -1
|
||||
var searchSuggestionEntryId: Long = -1
|
||||
var scrubbingId: Long = -1
|
||||
var slimMetadataToggleButtonId: Long = -1
|
||||
var suggestedActionId: Long = -1
|
||||
var totalTimeId: Long = -1
|
||||
var toolTipId: Long = -1
|
||||
var videoQualityFragmentId: Long = -1
|
||||
}
|
||||
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
|
||||
fun find(type: ResourceType, name: String) = ResourceMappingPatch
|
||||
.resourceMappings
|
||||
.single { it.type == type.value && it.name == name }.id
|
||||
|
||||
accessibilityProgressTimeId = find(STRING, "accessibility_player_progress_time")
|
||||
accountSwitcherAccessibilityId = find(STRING, "account_switcher_accessibility_label")
|
||||
adAttributionId = find(ID, "ad_attribution")
|
||||
appearanceStringId = find(STRING, "app_theme_appearance_dark")
|
||||
appRelatedEndScreenResultsId = find(LAYOUT, "app_related_endscreen_results")
|
||||
autoNavPreviewId = find(ID, "autonav_preview_stub")
|
||||
backgroundCategoryId = find(STRING, "pref_background_and_offline_category")
|
||||
barContainerHeightId = find(DIMEN, "bar_container_height")
|
||||
bottomUiContainerResourceId = find(ID, "bottom_ui_container_stub")
|
||||
channelListSubMenuId = find(LAYOUT, "channel_list_sub_menu")
|
||||
chapterRepeatOnResourceId = find(STRING, "chapter_repeat_on")
|
||||
compactLinkId = find(LAYOUT, "compact_link")
|
||||
controlsLayoutStubResourceId = find(ID, "controls_layout_stub")
|
||||
dislikeButtonId = find(ID, "dislike_button")
|
||||
donationCompanionResourceId = find(LAYOUT, "donation_companion")
|
||||
easySeekEduContainerId = find(ID, "easy_seek_edu_container")
|
||||
expandButtonId = find(LAYOUT, "expand_button_down")
|
||||
fabId = find(ID, "fab")
|
||||
filterBarHeightId = find(DIMEN, "filter_bar_height")
|
||||
floatyBarTopMarginId = find(DIMEN, "floaty_bar_button_top_margin")
|
||||
horizontalCardListId = find(LAYOUT, "horizontal_card_list")
|
||||
imageOnlyTabId = find(LAYOUT, "image_only_tab")
|
||||
inlineTimeBarColorizedBarPlayedColorDarkId = find(COLOR, "inline_time_bar_colorized_bar_played_color_dark")
|
||||
inlineTimeBarPlayedNotHighlightedColorId = find(COLOR, "inline_time_bar_played_not_highlighted_color")
|
||||
insetOverlayViewLayoutId = find(ID, "inset_overlay_view_layout")
|
||||
layoutCircleId = find(LAYOUT, "endscreen_element_layout_circle")
|
||||
layoutIconId = find(LAYOUT, "endscreen_element_layout_icon")
|
||||
layoutVideoId = find(LAYOUT, "endscreen_element_layout_video")
|
||||
likeButtonId = find(ID, "like_button")
|
||||
liveChatButtonId = find(ID, "live_chat_overlay_button")
|
||||
reelPlayerBadgeId = find(ID, "reel_player_badge")
|
||||
reelPlayerBadge2Id = find(ID, "reel_player_badge2")
|
||||
reelPlayerFooterId = find(LAYOUT, "reel_player_dyn_footer_vert_stories3")
|
||||
reelPlayerInfoPanelId = find(ID, "reel_player_info_panel")
|
||||
reelPlayerPausedId = find(ID, "reel_player_paused_state_buttons")
|
||||
reelRemixId = find(ID, "reel_dyn_remix")
|
||||
relatedChipCloudMarginId = find(LAYOUT, "related_chip_cloud_reduced_margins")
|
||||
rightCommentId = find(DRAWABLE, "ic_right_comment_32c")
|
||||
scrimOverlayId = find(ID, "scrim_overlay")
|
||||
searchSuggestionEntryId = find(LAYOUT, "search_suggestion_entry")
|
||||
scrubbingId = find(DIMEN, "vertical_touch_offset_to_enter_fine_scrubbing")
|
||||
slimMetadataToggleButtonId = find(COLOR, "slim_metadata_toggle_button")
|
||||
suggestedActionId = find(LAYOUT, "suggested_action")
|
||||
totalTimeId = find(STRING, "total_time")
|
||||
toolTipId = find(LAYOUT, "tooltip_content_view")
|
||||
videoQualityFragmentId = find(LAYOUT, "video_quality_bottom_sheet_list_fragment_title")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object DislikeFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
strings = listOf("like/dislike")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object LikeFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
strings = listOf("like/like")
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object RemoveLikeFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
strings = listOf("like/removelike")
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object TextComponentAtomicReferenceFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.MOVE_OBJECT
|
||||
)
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object TextComponentConstructorFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR,
|
||||
strings = listOf("TextComponent")
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object TextComponentContextFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT, // conversion context
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET_BOOLEAN
|
||||
)
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object TextComponentTmpFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT, // last instruction of the method
|
||||
)
|
||||
)
|
@ -1,142 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.general.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.returnyoutubedislike.general.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.patch.ReturnYouTubeDislikeOldLayoutPatch
|
||||
import app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.patch.ReturnYouTubeDislikeShortsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
|
||||
import app.revanced.util.integrations.Constants.UTILS_PATH
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import org.jf.dexlib2.iface.reference.Reference
|
||||
|
||||
@Patch
|
||||
@Name("return-youtube-dislike")
|
||||
@Description("Shows the dislike count of videos using the Return YouTube Dislike API.")
|
||||
@DependsOn(
|
||||
[
|
||||
MainstreamVideoIdPatch::class,
|
||||
ReturnYouTubeDislikeOldLayoutPatch::class,
|
||||
ReturnYouTubeDislikeShortsPatch::class,
|
||||
SettingsPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ReturnYouTubeDislikePatch : BytecodePatch(
|
||||
listOf(
|
||||
DislikeFingerprint,
|
||||
LikeFingerprint,
|
||||
RemoveLikeFingerprint,
|
||||
TextComponentConstructorFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
listOf(
|
||||
LikeFingerprint.toPatch(Vote.LIKE),
|
||||
DislikeFingerprint.toPatch(Vote.DISLIKE),
|
||||
RemoveLikeFingerprint.toPatch(Vote.REMOVE_LIKE)
|
||||
).forEach { (fingerprint, vote) ->
|
||||
with(fingerprint.result ?: return fingerprint.toErrorResult()) {
|
||||
mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, ${vote.value}
|
||||
invoke-static {v0}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->sendVote(I)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TextComponentConstructorFingerprint.result?.let { parentResult ->
|
||||
|
||||
TextComponentContextFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
with (it.mutableMethod) {
|
||||
val conversionContextIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
conversionContextFieldReference =
|
||||
getInstruction<ReferenceInstruction>(conversionContextIndex).reference
|
||||
}
|
||||
} ?: return TextComponentContextFingerprint.toErrorResult()
|
||||
|
||||
TextComponentTmpFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
tmpRegister =
|
||||
getInstruction<FiveRegisterInstruction>(startIndex).registerE
|
||||
}
|
||||
} ?: return TextComponentTmpFingerprint.toErrorResult()
|
||||
|
||||
|
||||
TextComponentAtomicReferenceFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
with (it.mutableMethod) {
|
||||
val atomicReferenceStartIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val moveCharSequenceInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
|
||||
|
||||
val atomicReferenceRegister =
|
||||
getInstruction<FiveRegisterInstruction>(atomicReferenceStartIndex).registerC
|
||||
|
||||
val charSequenceRegister =
|
||||
moveCharSequenceInstruction.registerB
|
||||
|
||||
replaceInstructions(insertIndex, "move-object/from16 v$tmpRegister, p0")
|
||||
addInstructions(
|
||||
insertIndex + 1, """
|
||||
iget-object v$tmpRegister, v$tmpRegister, $conversionContextFieldReference
|
||||
invoke-static {v$tmpRegister, v$atomicReferenceRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||
move-result-object v$charSequenceRegister
|
||||
move-object v${moveCharSequenceInstruction.registerA}, v${charSequenceRegister}
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return TextComponentAtomicReferenceFingerprint.toErrorResult()
|
||||
} ?: return TextComponentConstructorFingerprint.toErrorResult()
|
||||
|
||||
|
||||
MainstreamVideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
|
||||
|
||||
/**
|
||||
* Add ReVanced Settings
|
||||
*/
|
||||
SettingsPatch.addReVancedPreference("ryd_settings")
|
||||
|
||||
SettingsPatch.updatePatchStatus("return-youtube-dislike")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
private companion object {
|
||||
const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR =
|
||||
"$UTILS_PATH/ReturnYouTubeDislikePatch;"
|
||||
|
||||
lateinit var conversionContextFieldReference: Reference
|
||||
var tmpRegister: Int = 12
|
||||
}
|
||||
|
||||
private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind)
|
||||
|
||||
private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote)
|
||||
|
||||
private enum class Vote(val value: Int) {
|
||||
LIKE(1),
|
||||
DISLIKE(-1),
|
||||
REMOVE_LIKE(0)
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.dislikeButtonId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object ButtonTagFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(dislikeButtonId) }
|
||||
)
|
@ -1,14 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object ButtonTagOnClickFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT
|
||||
),
|
||||
customFingerprint = { it, _ -> it.name == "onClick" }
|
||||
)
|
@ -1,10 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.slimMetadataToggleButtonId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
|
||||
object SlimMetadataButtonParentFingerprint : MethodFingerprint(
|
||||
returnType = "I",
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(slimMetadataToggleButtonId) }
|
||||
)
|
@ -1,17 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SlimMetadataButtonTextFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf(),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET
|
||||
)
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object SlimMetadataButtonViewFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf(),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.RETURN_OBJECT
|
||||
)
|
||||
)
|
@ -1,118 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.dislikeButtonId
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.likeButtonId
|
||||
import app.revanced.patches.youtube.misc.returnyoutubedislike.oldlayout.fingerprints.*
|
||||
import app.revanced.util.bytecode.getWideLiteralIndex
|
||||
import app.revanced.util.integrations.Constants.UTILS_PATH
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import org.jf.dexlib2.iface.reference.Reference
|
||||
|
||||
@Name("return-youtube-dislike-old-layout")
|
||||
@DependsOn([SharedResourceIdPatch::class])
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ReturnYouTubeDislikeOldLayoutPatch : BytecodePatch(
|
||||
listOf(
|
||||
SlimMetadataButtonParentFingerprint,
|
||||
ButtonTagFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
SlimMetadataButtonParentFingerprint.result?.let { parentResult ->
|
||||
|
||||
SlimMetadataButtonViewFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
slimMetadataButtonViewFieldReference =
|
||||
getInstruction<ReferenceInstruction>(startIndex).reference
|
||||
}
|
||||
} ?: return SlimMetadataButtonViewFingerprint.toErrorResult()
|
||||
|
||||
SlimMetadataButtonTextFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val setTextInstruction = getInstruction<FiveRegisterInstruction>(insertIndex)
|
||||
|
||||
val tempRegister =
|
||||
setTextInstruction.registerC + 1
|
||||
|
||||
val charSequenceRegister =
|
||||
setTextInstruction.registerD
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
iget-object v$tempRegister, p0, $slimMetadataButtonViewFieldReference
|
||||
invoke-static {v$tempRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onSetText(Landroid/view/View;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||
move-result-object v$charSequenceRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return SlimMetadataButtonTextFingerprint.toErrorResult()
|
||||
} ?: return SlimMetadataButtonParentFingerprint.toErrorResult()
|
||||
|
||||
|
||||
ButtonTagFingerprint.result?.let { parentResult ->
|
||||
|
||||
ButtonTagOnClickFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
getActiveBooleanFieldReference =
|
||||
getInstruction<ReferenceInstruction>(startIndex).reference
|
||||
}
|
||||
} ?: return ButtonTagOnClickFingerprint.toErrorResult()
|
||||
|
||||
parentResult.mutableMethod.apply {
|
||||
val dislikeButtonIndex = getWideLiteralIndex(dislikeButtonId)
|
||||
val dislikeButtonRegister = getInstruction<OneRegisterInstruction>(dislikeButtonIndex).registerA
|
||||
val dislikeButtonInstruction = getInstruction<TwoRegisterInstruction>(dislikeButtonIndex - 1)
|
||||
|
||||
addInstructions(
|
||||
dislikeButtonIndex, """
|
||||
invoke-virtual {v${dislikeButtonInstruction.registerB}}, $getActiveBooleanFieldReference
|
||||
move-result v$dislikeButtonRegister
|
||||
invoke-static {v${dislikeButtonInstruction.registerA}, v$dislikeButtonRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->setDislikeTag(Landroid/view/View;Z)V
|
||||
"""
|
||||
)
|
||||
|
||||
val likeButtonIndex = getWideLiteralIndex(likeButtonId)
|
||||
val likeButtonRegister = getInstruction<OneRegisterInstruction>(likeButtonIndex).registerA
|
||||
val likeButtonInstruction = getInstruction<TwoRegisterInstruction>(likeButtonIndex - 1)
|
||||
|
||||
addInstructions(
|
||||
likeButtonIndex, """
|
||||
invoke-virtual {v${likeButtonInstruction.registerB}}, $getActiveBooleanFieldReference
|
||||
move-result v$likeButtonRegister
|
||||
invoke-static {v${likeButtonInstruction.registerA}, v$likeButtonRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->setLikeTag(Landroid/view/View;Z)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return ButtonTagFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
private companion object {
|
||||
const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR =
|
||||
"$UTILS_PATH/ReturnYouTubeDislikePatch;"
|
||||
|
||||
lateinit var slimMetadataButtonViewFieldReference: Reference
|
||||
lateinit var getActiveBooleanFieldReference: Reference
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object ShortsTextComponentParentFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("L", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.GOTO,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.INVOKE_STATIC
|
||||
)
|
||||
)
|
@ -1,61 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.toMethodWalker
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.returnyoutubedislike.shorts.fingerprints.ShortsTextComponentParentFingerprint
|
||||
import app.revanced.util.integrations.Constants.UTILS_PATH
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("return-youtube-dislike-shorts")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class ReturnYouTubeDislikeShortsPatch : BytecodePatch(
|
||||
listOf(ShortsTextComponentParentFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
ShortsTextComponentParentFingerprint.result?.let {
|
||||
(context
|
||||
.toMethodWalker(it.method)
|
||||
.nextMethod(it.scanResult.patternScanResult!!.endIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
).apply {
|
||||
val insertIndex = implementation!!.instructions.size - 1
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
this.insertShorts(insertIndex, insertRegister)
|
||||
}
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
|
||||
this.insertShorts(insertIndex, insertRegister)
|
||||
}
|
||||
} ?: return ShortsTextComponentParentFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
private companion object {
|
||||
const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR =
|
||||
"$UTILS_PATH/ReturnYouTubeDislikePatch;"
|
||||
}
|
||||
|
||||
private fun MutableMethod.insertShorts(index: Int, register: Int) {
|
||||
addInstructions(
|
||||
index, """
|
||||
invoke-static {v$register}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onShortsComponentCreated(Landroid/text/Spanned;)Landroid/text/Spanned;
|
||||
move-result-object v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.appearanceStringId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object ThemeSetterSystemFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
opcodes = listOf(Opcode.RETURN_OBJECT),
|
||||
customFingerprint = { it, _ -> it.isWideLiteralExists(appearanceStringId) }
|
||||
)
|
@ -1,62 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.settings.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint
|
||||
import app.revanced.util.bytecode.BytecodeHelper.injectInit
|
||||
import app.revanced.util.integrations.Constants.INTEGRATIONS_PATH
|
||||
|
||||
@Name("settings-bytecode-patch")
|
||||
@DependsOn(
|
||||
[
|
||||
IntegrationsPatch::class,
|
||||
ResourceMappingPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class SettingsBytecodePatch : BytecodePatch(
|
||||
listOf(ThemeSetterSystemFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
// apply the current theme of the settings page
|
||||
ThemeSetterSystemFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
replaceInstruction(
|
||||
targetIndex,
|
||||
SET_THEME
|
||||
)
|
||||
addInstruction(
|
||||
targetIndex + 1,
|
||||
"return-object v0"
|
||||
)
|
||||
addInstruction(
|
||||
this.implementation!!.instructions.size - 1,
|
||||
SET_THEME
|
||||
)
|
||||
}
|
||||
} ?: return ThemeSetterSystemFingerprint.toErrorResult()
|
||||
|
||||
context.injectInit("FirstRun", "initializationRVX")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
companion object {
|
||||
const val SET_THEME =
|
||||
"invoke-static {v0}, $INTEGRATIONS_PATH/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V"
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.settings.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.settings.AbstractSettingsResourcePatch
|
||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsBytecodePatch
|
||||
import app.revanced.util.resources.IconHelper.YOUTUBE_LAUNCHER_ICON_ARRAY
|
||||
import app.revanced.util.resources.IconHelper.copyFiles
|
||||
import app.revanced.util.resources.IconHelper.makeDirectoryAndCopyFiles
|
||||
import app.revanced.util.resources.ResourceHelper.addPreference
|
||||
import app.revanced.util.resources.ResourceHelper.addReVancedPreference
|
||||
import app.revanced.util.resources.ResourceHelper.updatePatchStatus
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
import org.w3c.dom.Element
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
@Patch
|
||||
@Name("settings")
|
||||
@Description("Applies mandatory patches to implement ReVanced settings into the application.")
|
||||
@DependsOn(
|
||||
[
|
||||
IntegrationsPatch::class,
|
||||
SharedResourceIdPatch::class,
|
||||
SettingsBytecodePatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class SettingsPatch : AbstractSettingsResourcePatch(
|
||||
"youtube/settings",
|
||||
"youtube/settings/host",
|
||||
true
|
||||
) {
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
super.execute(context)
|
||||
contexts = context
|
||||
|
||||
/**
|
||||
* create directory for the untranslated language resources
|
||||
*/
|
||||
context["res/values-v21"].mkdirs()
|
||||
|
||||
arrayOf(
|
||||
ResourceUtils.ResourceGroup(
|
||||
"layout",
|
||||
"revanced_settings_toolbar.xml",
|
||||
"revanced_settings_with_toolbar.xml",
|
||||
"revanced_settings_with_toolbar_layout.xml"
|
||||
),
|
||||
ResourceUtils.ResourceGroup(
|
||||
"values-v21",
|
||||
"strings.xml"
|
||||
)
|
||||
).forEach { resourceGroup ->
|
||||
context.copyResources("youtube/settings", resourceGroup)
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize ReVanced Settings
|
||||
*/
|
||||
addReVancedPreference("extended_settings")
|
||||
|
||||
/**
|
||||
* remove revanced settings divider
|
||||
*/
|
||||
arrayOf("Theme.YouTube.Settings", "Theme.YouTube.Settings.Dark").forEach { themeName ->
|
||||
context.xmlEditor["res/values/styles.xml"].use { editor ->
|
||||
with(editor.file) {
|
||||
val resourcesNode = getElementsByTagName("resources").item(0) as Element
|
||||
|
||||
val newElement: Element = createElement("item")
|
||||
newElement.setAttribute("name", "android:listDivider")
|
||||
|
||||
for (i in 0 until resourcesNode.childNodes.length) {
|
||||
val node = resourcesNode.childNodes.item(i) as? Element ?: continue
|
||||
|
||||
if (node.getAttribute("name") == themeName) {
|
||||
newElement.appendChild(createTextNode("@null"))
|
||||
|
||||
node.appendChild(newElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a custom branding icon path exists, merge it
|
||||
*/
|
||||
val iconPath = "branding"
|
||||
val targetDirectory = Paths.get("").toAbsolutePath().toString() + "/$iconPath"
|
||||
|
||||
if (File(targetDirectory).exists()) {
|
||||
fun copyResources(resourceGroups: List<ResourceUtils.ResourceGroup>) {
|
||||
try { context.copyFiles(resourceGroups, iconPath) }
|
||||
catch (_: Exception) { context.makeDirectoryAndCopyFiles(resourceGroups, iconPath) }
|
||||
}
|
||||
|
||||
val iconResourceFileNames =
|
||||
YOUTUBE_LAUNCHER_ICON_ARRAY
|
||||
.map { "$it.png" }
|
||||
.toTypedArray()
|
||||
|
||||
fun createGroup(directory: String) = ResourceUtils.ResourceGroup(
|
||||
directory, *iconResourceFileNames
|
||||
)
|
||||
|
||||
arrayOf("xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi")
|
||||
.map { "mipmap-$it" }
|
||||
.map(::createGroup)
|
||||
.let(::copyResources)
|
||||
}
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
companion object {
|
||||
internal lateinit var contexts: ResourceContext
|
||||
|
||||
internal fun addPreference(settingArray: Array<String>) {
|
||||
contexts.addPreference(settingArray)
|
||||
}
|
||||
|
||||
internal fun addReVancedPreference(key: String) {
|
||||
contexts.addReVancedPreference(key)
|
||||
}
|
||||
|
||||
internal fun updatePatchStatus(patchTitle: String) {
|
||||
contexts.updatePatchStatus(patchTitle)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object EndScreenEngagementPanelsFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
opcodes = listOf(Opcode.CONST_WIDE_16),
|
||||
strings = listOf("ITEM_COUNT")
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.insetOverlayViewLayoutId
|
||||
import app.revanced.util.bytecode.isWideLiteralExists
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object OverlayViewLayoutFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST
|
||||
),
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("YouTubeControlsOverlay;") && it.isWideLiteralExists(insetOverlayViewLayoutId) }
|
||||
)
|
@ -1,7 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PlayerControllerFingerprint : MethodFingerprint(
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("SegmentPlaybackController;") && it.name == "setSponsorBarRect" }
|
||||
)
|
@ -1,255 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.fingerprints.TotalTimeFingerprint
|
||||
import app.revanced.patches.youtube.misc.overridespeed.bytecode.patch.OverrideSpeedHookPatch
|
||||
import app.revanced.patches.youtube.misc.playercontrols.patch.PlayerControlsPatch
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.insetOverlayViewLayoutId
|
||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.totalTimeId
|
||||
import app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints.*
|
||||
import app.revanced.patches.youtube.misc.timebar.patch.HookTimeBarPatch
|
||||
import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch
|
||||
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
|
||||
import app.revanced.util.bytecode.BytecodeHelper.injectInit
|
||||
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus
|
||||
import app.revanced.util.bytecode.getWideLiteralIndex
|
||||
import org.jf.dexlib2.Opcode
|
||||
import org.jf.dexlib2.builder.BuilderInstruction
|
||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction3rc
|
||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||
import org.jf.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Name("sponsorblock-bytecode-patch")
|
||||
@DependsOn(
|
||||
[
|
||||
HookTimeBarPatch::class,
|
||||
LegacyVideoIdPatch::class,
|
||||
MainstreamVideoIdPatch::class,
|
||||
OverrideSpeedHookPatch::class,
|
||||
PlayerControlsPatch::class,
|
||||
SharedResourceIdPatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class SponsorBlockBytecodePatch : BytecodePatch(
|
||||
listOf(
|
||||
EndScreenEngagementPanelsFingerprint,
|
||||
OverlayViewLayoutFingerprint,
|
||||
PlayerControllerFingerprint,
|
||||
TotalTimeFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
/**
|
||||
* Hook the video time methods
|
||||
*/
|
||||
MainstreamVideoIdPatch.apply {
|
||||
videoTimeHook(
|
||||
INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR,
|
||||
"setVideoTime"
|
||||
)
|
||||
onCreateHook(
|
||||
INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR,
|
||||
"initialize"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Seekbar drawing
|
||||
*/
|
||||
insertMethod = HookTimeBarPatch.setTimeBarMethod
|
||||
insertInstructions = insertMethod.implementation!!.instructions
|
||||
|
||||
|
||||
/**
|
||||
* Get the instance of the seekbar rectangle
|
||||
*/
|
||||
for ((index, instruction) in insertInstructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_DIRECT_RANGE) continue
|
||||
insertMethod.addInstruction(
|
||||
index,
|
||||
"invoke-static/range {p0 .. p0}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
for ((index, instruction) in insertInstructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_STATIC) continue
|
||||
|
||||
val invokeInstruction = insertMethod.getInstruction<Instruction35c>(index)
|
||||
if ((invokeInstruction.reference as MethodReference).name != "round") continue
|
||||
|
||||
val insertIndex = index + 2
|
||||
|
||||
insertMethod.addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
/**
|
||||
* Set rectangle absolute left and right positions
|
||||
*/
|
||||
val drawRectangleInstructions = insertInstructions.filter {
|
||||
it is ReferenceInstruction && (it.reference as? MethodReference)?.name == "drawRect" && it is FiveRegisterInstruction
|
||||
}.map { // TODO: improve code
|
||||
insertInstructions.indexOf(it) to (it as FiveRegisterInstruction).registerD
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in YouTube v18.17.43+.
|
||||
* TODO: remove code from integrations
|
||||
*/
|
||||
if (drawRectangleInstructions.size > 3) {
|
||||
mapOf(
|
||||
"setSponsorBarAbsoluteLeft" to 3,
|
||||
"setSponsorBarAbsoluteRight" to 0
|
||||
).forEach { (string, int) ->
|
||||
val (index, register) = drawRectangleInstructions[int]
|
||||
injectCallRectangle(index, register, string)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw segment
|
||||
*/
|
||||
for ((index, instruction) in insertInstructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL_RANGE) continue
|
||||
|
||||
val invokeInstruction = instruction as BuilderInstruction3rc
|
||||
if ((invokeInstruction.reference as MethodReference).name != "restore") continue
|
||||
|
||||
val drawSegmentInstructionInsertIndex = index - 1
|
||||
|
||||
val (canvasInstance, centerY) =
|
||||
insertMethod.getInstruction<FiveRegisterInstruction>(drawSegmentInstructionInsertIndex).let { it.registerC to it.registerE }
|
||||
|
||||
insertMethod.addInstruction(
|
||||
drawSegmentInstructionInsertIndex,
|
||||
"invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
/**
|
||||
* Voting & Shield button
|
||||
*/
|
||||
arrayOf("CreateSegmentButtonController", "VotingButtonController").forEach {
|
||||
PlayerControlsPatch.initializeSB("$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/ui/$it;")
|
||||
PlayerControlsPatch.injectVisibility("$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/ui/$it;")
|
||||
}
|
||||
|
||||
EndScreenEngagementPanelsFingerprint.result?.mutableMethod?.let {
|
||||
it.addInstruction(
|
||||
it.implementation!!.instructions.size - 1,
|
||||
"invoke-static {}, $INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/ui/SponsorBlockViewController;->endOfVideoReached()V"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the new time to the player layout
|
||||
*/
|
||||
TotalTimeFingerprint.result?.mutableMethod?.let {
|
||||
it.apply {
|
||||
val targetIndex = getWideLiteralIndex(totalTimeId) + 2
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
targetIndex + 1, """
|
||||
invoke-static {v$targetRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$targetRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
} ?: return TotalTimeFingerprint.toErrorResult()
|
||||
|
||||
/**
|
||||
* Initialize the SponsorBlock view
|
||||
*/
|
||||
OverlayViewLayoutFingerprint.result?.mutableMethod?.let{
|
||||
it.apply{
|
||||
val targetIndex = getWideLiteralIndex(insetOverlayViewLayoutId) + 3
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
targetIndex + 1,
|
||||
"invoke-static {v$targetRegister}, $INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/ui/SponsorBlockViewController;->initialize(Landroid/view/ViewGroup;)V"
|
||||
)
|
||||
}
|
||||
} ?: return OverlayViewLayoutFingerprint.toErrorResult()
|
||||
|
||||
/**
|
||||
* Replace strings
|
||||
*/
|
||||
PlayerControllerFingerprint.result?.mutableMethod?.let {
|
||||
val instructions = it.implementation!!.instructions
|
||||
|
||||
for ((index, instruction) in instructions.withIndex()) {
|
||||
if (instruction.opcode != Opcode.CONST_STRING) continue
|
||||
val register = it.getInstruction<OneRegisterInstruction>(index).registerA
|
||||
it.replaceInstruction(
|
||||
index,
|
||||
"const-string v$register, \"${MainstreamVideoIdPatch.reactReference}\""
|
||||
)
|
||||
break
|
||||
}
|
||||
} ?: return PlayerControllerFingerprint.toErrorResult()
|
||||
|
||||
/**
|
||||
* Inject VideoIdPatch
|
||||
*/
|
||||
LegacyVideoIdPatch.injectCall("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V")
|
||||
|
||||
context.injectInit("FirstRun", "initializationSB")
|
||||
context.updatePatchStatus("SponsorBlock")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
const val INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/sponsorblock"
|
||||
|
||||
const val INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR =
|
||||
"$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/SegmentPlaybackController;"
|
||||
|
||||
lateinit var insertMethod: MutableMethod
|
||||
lateinit var insertInstructions: List<BuilderInstruction>
|
||||
|
||||
/**
|
||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
fun injectCallRectangle(
|
||||
insertIndex: Int,
|
||||
targetRegister: Int,
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static {v$targetRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->$methodDescriptor(Landroid/graphics/Rect;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.sponsorblock.resource.patch
|
||||
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch.SponsorBlockBytecodePatch
|
||||
import app.revanced.util.resources.ResourceUtils
|
||||
import app.revanced.util.resources.ResourceUtils.copyResources
|
||||
import app.revanced.util.resources.ResourceUtils.copyXmlNode
|
||||
|
||||
@Patch
|
||||
@Name("sponsorblock")
|
||||
@Description("Integrates SponsorBlock which allows skipping video segments such as sponsored content.")
|
||||
@DependsOn(
|
||||
[
|
||||
SettingsPatch::class,
|
||||
SponsorBlockBytecodePatch::class
|
||||
]
|
||||
)
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class SponsorBlockResourcePatch : ResourcePatch {
|
||||
|
||||
override fun execute(context: ResourceContext): PatchResult {
|
||||
/**
|
||||
* merge SponsorBlock drawables to main drawables
|
||||
*/
|
||||
|
||||
arrayOf(
|
||||
ResourceUtils.ResourceGroup(
|
||||
"layout",
|
||||
"inline_sponsor_overlay.xml",
|
||||
"new_segment.xml",
|
||||
"skip_sponsor_button.xml"
|
||||
),
|
||||
ResourceUtils.ResourceGroup(
|
||||
// required resource for back button, because when the base APK is used, this resource will not exist
|
||||
"drawable",
|
||||
"ic_sb_adjust.xml",
|
||||
"ic_sb_compare.xml",
|
||||
"ic_sb_edit.xml",
|
||||
"ic_sb_logo.xml",
|
||||
"ic_sb_publish.xml",
|
||||
"ic_sb_voting.xml"
|
||||
)
|
||||
).forEach { resourceGroup ->
|
||||
context.copyResources("youtube/sponsorblock", resourceGroup)
|
||||
}
|
||||
|
||||
/**
|
||||
* merge xml nodes from the host to their real xml files
|
||||
*/
|
||||
|
||||
// collect all host resources
|
||||
val hostingXmlResources = mapOf("layout" to arrayOf("youtube_controls_layout"))
|
||||
|
||||
// copy nodes from host resources to their real xml files
|
||||
hostingXmlResources.forEach { (path, resources) ->
|
||||
resources.forEach { resource ->
|
||||
val hostingResourceStream = this.javaClass.classLoader.getResourceAsStream("youtube/sponsorblock/host/$path/$resource.xml")!!
|
||||
|
||||
val targetXmlEditor = context.xmlEditor["res/$path/$resource.xml"]
|
||||
"RelativeLayout".copyXmlNode(
|
||||
context.xmlEditor[hostingResourceStream],
|
||||
targetXmlEditor
|
||||
).also {
|
||||
val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes
|
||||
|
||||
// Replace the startOf with the voting button view so that the button does not overlap
|
||||
for (i in 1 until children.length) {
|
||||
val view = children.item(i)
|
||||
|
||||
// Replace the attribute for a specific node only
|
||||
if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("player_video_heading"))) continue
|
||||
|
||||
// voting button id from the voting button view from the youtube_controls_layout.xml host file
|
||||
val votingButtonId = "@+id/sb_voting_button"
|
||||
|
||||
view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId
|
||||
|
||||
break
|
||||
}
|
||||
}.close() // close afterwards
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ReVanced Settings
|
||||
*/
|
||||
SettingsPatch.addReVancedPreference("sponsorblock_settings")
|
||||
|
||||
SettingsPatch.updatePatchStatus("sponsorblock")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.shared.patch.versionspoof.GeneralVersionSpoofPatch
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.integrations.Constants.MISC_PATH
|
||||
import app.revanced.util.resources.ResourceUtils.copyXmlNode
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.timebar.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object EmptyColorFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.CMP_LONG,
|
||||
Opcode.IF_LEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.GOTO,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE
|
||||
)
|
||||
)
|
@ -1,17 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.timebar.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object OnDrawFingerprint : MethodFingerprint (
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.MOVE_OBJECT_FROM16
|
||||
),
|
||||
customFingerprint = { it, _ -> it.name == "onDraw"}
|
||||
)
|
@ -1,41 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.timebar.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.timebar.fingerprints.*
|
||||
|
||||
@Name("hook-timebar-patch")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class HookTimeBarPatch : BytecodePatch(
|
||||
listOf(EmptyColorFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
EmptyColorFingerprint.result?.let { parentResult ->
|
||||
emptyColorResult = parentResult
|
||||
emptyColorMethod = parentResult.mutableMethod
|
||||
OnDrawFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.let {
|
||||
setTimeBarMethod = it
|
||||
} ?: return OnDrawFingerprint.toErrorResult()
|
||||
} ?: return EmptyColorFingerprint.toErrorResult()
|
||||
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
internal companion object {
|
||||
lateinit var emptyColorResult: MethodFingerprintResult
|
||||
lateinit var emptyColorMethod: MutableMethod
|
||||
lateinit var setTimeBarMethod: MutableMethod
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.patch.annotations.Patch
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
|
||||
import app.revanced.util.resources.ResourceHelper.addTranslations
|
||||
|
||||
@Patch
|
||||
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.legacy.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object LegacyVideoIdFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(Opcode.INVOKE_INTERFACE),
|
||||
customFingerprint = { it, _ ->
|
||||
it.definingClass.endsWith("PlaybackLifecycleMonitor;")
|
||||
}
|
||||
)
|
@ -1,65 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.legacy.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.videoid.legacy.fingerprint.LegacyVideoIdFingerprint
|
||||
import app.revanced.util.integrations.Constants.VIDEO_PATH
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Name("video-id-hook-legacy")
|
||||
@Description("Hook to detect when the video id changes (legacy)")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
class LegacyVideoIdPatch : BytecodePatch(
|
||||
listOf(LegacyVideoIdFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
LegacyVideoIdFingerprint.result?.let {
|
||||
insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
it.mutableMethod.apply {
|
||||
insertMethod = this
|
||||
videoIdRegister = (implementation!!.instructions[insertIndex + 1] as OneRegisterInstruction).registerA
|
||||
}
|
||||
offset++ // offset so setCurrentVideoId is called before any injected call
|
||||
} ?: return LegacyVideoIdFingerprint.toErrorResult()
|
||||
|
||||
injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR = "$VIDEO_PATH/VideoInformation;"
|
||||
private var offset = 2
|
||||
|
||||
private var insertIndex: Int = 0
|
||||
private var videoIdRegister: Int = 0
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
|
||||
|
||||
/**
|
||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
insertIndex + offset, // move-result-object offset
|
||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object MainstreamVideoIdFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT
|
||||
),
|
||||
customFingerprint = { it, _ -> it.definingClass.endsWith("SubtitlesOverlayPresenter;") }
|
||||
)
|
@ -1,12 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object PlayerControllerSetTimeReferenceFingerprint : MethodFingerprint(
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_DIRECT_RANGE,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf("Media progress reported outside media playback: ")
|
||||
)
|
@ -1,9 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object PlayerInitFingerprint : MethodFingerprint(
|
||||
strings = listOf(
|
||||
"playVideo called on player response with no videoStreamingData."
|
||||
),
|
||||
)
|
@ -1,7 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object SeekFingerprint : MethodFingerprint(
|
||||
strings = listOf("Attempting to seek during an ad")
|
||||
)
|
@ -1,15 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
|
||||
object TimebarFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
customFingerprint = { it, _ ->
|
||||
it.definingClass.endsWith("/TimeBar;")
|
||||
&& it.name.contains("draw")
|
||||
}
|
||||
)
|
@ -1,19 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.Opcode
|
||||
|
||||
object VideoTimeHighPrecisionFingerprint : MethodFingerprint (
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
parameters = listOf("J", "J", "J", "J", "I", "L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_WIDE,
|
||||
Opcode.IPUT_WIDE,
|
||||
Opcode.IPUT_WIDE,
|
||||
Opcode.IPUT_WIDE,
|
||||
)
|
||||
)
|
@ -1,7 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint
|
||||
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||
|
||||
object VideoTimeHighPrecisionParentFingerprint : MethodFingerprint(
|
||||
strings = listOf("MedialibPlayerTimeInfo{currentPositionMillis=")
|
||||
)
|
@ -1,236 +0,0 @@
|
||||
package app.revanced.patches.youtube.misc.videoid.mainstream.patch
|
||||
|
||||
import app.revanced.extensions.toErrorResult
|
||||
import app.revanced.patcher.annotation.Description
|
||||
import app.revanced.patcher.annotation.Name
|
||||
import app.revanced.patcher.annotation.Version
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.toMethodWalker
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchResult
|
||||
import app.revanced.patcher.patch.PatchResultSuccess
|
||||
import app.revanced.patcher.patch.annotations.DependsOn
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.shared.annotation.YouTubeCompatibility
|
||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.timebar.patch.HookTimeBarPatch
|
||||
import app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint.*
|
||||
import app.revanced.util.integrations.Constants.VIDEO_PATH
|
||||
import org.jf.dexlib2.AccessFlags
|
||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
|
||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import org.jf.dexlib2.iface.reference.FieldReference
|
||||
import org.jf.dexlib2.iface.reference.MethodReference
|
||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||
import org.jf.dexlib2.immutable.ImmutableMethodParameter
|
||||
import org.jf.dexlib2.util.MethodUtil
|
||||
|
||||
@Name("video-id-hook-mainstream")
|
||||
@Description("Hook to detect when the video id changes (mainstream)")
|
||||
@YouTubeCompatibility
|
||||
@Version("0.0.1")
|
||||
@DependsOn(
|
||||
[
|
||||
HookTimeBarPatch::class,
|
||||
PlayerTypeHookPatch::class
|
||||
]
|
||||
)
|
||||
class MainstreamVideoIdPatch : BytecodePatch(
|
||||
listOf(
|
||||
MainstreamVideoIdFingerprint,
|
||||
PlayerControllerSetTimeReferenceFingerprint,
|
||||
PlayerInitFingerprint,
|
||||
SeekFingerprint,
|
||||
TimebarFingerprint,
|
||||
VideoTimeHighPrecisionFingerprint,
|
||||
VideoTimeHighPrecisionParentFingerprint
|
||||
)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext): PatchResult {
|
||||
|
||||
PlayerInitFingerprint.result?.let { parentResult ->
|
||||
playerInitMethod = parentResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
||||
|
||||
// hook the player controller for use through integrations
|
||||
onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize")
|
||||
|
||||
SeekFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||
val resultMethod = it.method
|
||||
|
||||
with (it.mutableMethod) {
|
||||
val seekHelperMethod = ImmutableMethod(
|
||||
resultMethod.definingClass,
|
||||
"seekTo",
|
||||
listOf(ImmutableMethodParameter("J", null, "time")),
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
null, null,
|
||||
MutableMethodImplementation(4)
|
||||
).toMutable()
|
||||
|
||||
val seekSourceEnumType = resultMethod.parameterTypes[1].toString()
|
||||
|
||||
seekHelperMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
||||
invoke-virtual {p0, p1, p2, v0}, ${resultMethod.definingClass}->${resultMethod.name}(J$seekSourceEnumType)Z
|
||||
move-result p1
|
||||
return p1
|
||||
"""
|
||||
)
|
||||
|
||||
parentResult.mutableClass.methods.add(seekHelperMethod)
|
||||
}
|
||||
} ?: return SeekFingerprint.toErrorResult()
|
||||
} ?: return PlayerInitFingerprint.toErrorResult()
|
||||
|
||||
/**
|
||||
* Set the high precision video time method
|
||||
*/
|
||||
VideoTimeHighPrecisionParentFingerprint.result?.let { parentResult ->
|
||||
VideoTimeHighPrecisionFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.let { method ->
|
||||
highPrecisionTimeMethod = method
|
||||
} ?: return VideoTimeHighPrecisionFingerprint.toErrorResult()
|
||||
} ?: return VideoTimeHighPrecisionParentFingerprint.toErrorResult()
|
||||
|
||||
/**
|
||||
* Hook the methods which set the time
|
||||
*/
|
||||
highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime")
|
||||
|
||||
/**
|
||||
* Set current video time
|
||||
*/
|
||||
PlayerControllerSetTimeReferenceFingerprint.result?.let {
|
||||
timeMethod = context.toMethodWalker(it.method)
|
||||
.nextMethod(it.scanResult.patternScanResult!!.startIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
} ?: return PlayerControllerSetTimeReferenceFingerprint.toErrorResult()
|
||||
|
||||
|
||||
with (HookTimeBarPatch.emptyColorMethod) {
|
||||
val timeBarResult = TimebarFingerprint.result ?: return TimebarFingerprint.toErrorResult()
|
||||
val timeBarInstructions = timeBarResult.method.implementation!!.instructions
|
||||
val timeBarReference =
|
||||
(timeBarInstructions.elementAt(2) as ReferenceInstruction).reference as MethodReference
|
||||
|
||||
val instructions = implementation!!.instructions
|
||||
|
||||
reactReference =
|
||||
((instructions.elementAt(instructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name
|
||||
|
||||
for ((index, instruction) in instructions.withIndex()) {
|
||||
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? DexBackedMethodReference
|
||||
if (fieldReference?.let { it.name == timeBarReference.name } == true) {
|
||||
val primaryRegister = (instructions.elementAt(index + 1) as OneRegisterInstruction).registerA
|
||||
val secondaryRegister = primaryRegister + 1
|
||||
addInstruction(
|
||||
index + 3,
|
||||
"invoke-static {v$primaryRegister, v$secondaryRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V"
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MainstreamVideoIdFingerprint.result?.let {
|
||||
insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
|
||||
with (it.mutableMethod) {
|
||||
insertMethod = this
|
||||
videoIdRegister = (implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA
|
||||
}
|
||||
offset++ // offset so setVideoId is called before any injected call
|
||||
} ?: return MainstreamVideoIdFingerprint.toErrorResult()
|
||||
|
||||
return PatchResultSuccess()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val INTEGRATIONS_CLASS_DESCRIPTOR = "$VIDEO_PATH/VideoInformation;"
|
||||
internal var reactReference: String? = null
|
||||
|
||||
private var offset = 0
|
||||
private var playerInitInsertIndex = 4
|
||||
private var timeInitInsertIndex = 2
|
||||
private var highPrecisionInsertIndex = 0
|
||||
|
||||
private var insertIndex: Int = 0
|
||||
private var videoIdRegister: Int = 0
|
||||
private lateinit var insertMethod: MutableMethod
|
||||
private lateinit var playerInitMethod: MutableMethod
|
||||
private lateinit var timeMethod: MutableMethod
|
||||
private lateinit var highPrecisionTimeMethod: MutableMethod
|
||||
|
||||
/**
|
||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||
*/
|
||||
fun injectCall(
|
||||
methodDescriptor: String
|
||||
) {
|
||||
insertMethod.addInstructions(
|
||||
insertIndex + offset, // move-result-object offset
|
||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) =
|
||||
addInstruction(insertIndex, "invoke-static { $register }, $descriptor")
|
||||
|
||||
private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) =
|
||||
insert(insertIndex, "p1, p2", descriptor)
|
||||
|
||||
/**
|
||||
* Hook the player controller. Called when a video is opened or the current video is changed.
|
||||
*
|
||||
* Note: This hook is called very early and is called before the video id, video time, video length,
|
||||
* and many other data fields are set.
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the class to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) =
|
||||
playerInitMethod.insert(
|
||||
playerInitInsertIndex++,
|
||||
"v0",
|
||||
"$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V"
|
||||
)
|
||||
|
||||
/**
|
||||
* Hook the video time.
|
||||
* The hook is usually called once per second.
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the static method to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||
timeMethod.insertTimeHook(
|
||||
timeInitInsertIndex++,
|
||||
"$targetMethodClass->$targetMethodName(J)V"
|
||||
)
|
||||
|
||||
/**
|
||||
* Hook the high precision video time.
|
||||
* The hooks is called extremely often (10 to 15 times a seconds), so use with caution.
|
||||
* Note: the hook is usually called _off_ the main thread
|
||||
*
|
||||
* @param targetMethodClass The descriptor for the static method to invoke when the player controller is created.
|
||||
* @param targetMethodName The name of the static method to invoke when the player controller is created.
|
||||
*/
|
||||
internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) =
|
||||
highPrecisionTimeMethod.insertTimeHook(
|
||||
highPrecisionInsertIndex++,
|
||||
"$targetMethodClass->$targetMethodName(J)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user