refactor: move the patch to the correct path

This commit is contained in:
inotia00
2023-06-18 23:09:08 +09:00
parent 03148b5c81
commit 5c99e9a16a
410 changed files with 3807 additions and 3505 deletions

View File

@ -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()
/**

View File

@ -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 "),
)

View File

@ -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()
}
}

View File

@ -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()
}
/**

View File

@ -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()

View File

@ -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")
)

View File

@ -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 }
)

View File

@ -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",
),
)

View File

@ -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),
)

View File

@ -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

View File

@ -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(
[

View File

@ -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.")
)

View File

@ -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")
)

View File

@ -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: ")
)

View File

@ -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")
)

View File

@ -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")
)

View File

@ -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 ")
)

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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"
}

View File

@ -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) }
)

View File

@ -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
"""
"""
)
}

View File

@ -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()
}
/**

View File

@ -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")
)

View File

@ -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" }
)

View File

@ -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
)
)

View File

@ -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"}
)

View File

@ -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")
)

View File

@ -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
}
}

View File

@ -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()
}
}

View File

@ -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) }
)

View File

@ -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()
}
}

View File

@ -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) }
)

View File

@ -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) }
)

View File

@ -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;") }
)

View File

@ -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:")
)

View File

@ -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)
}
}
)

View File

@ -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)
}
}
)

View File

@ -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)
}
}
}

View File

@ -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"
}
)

View File

@ -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()
}
}

View File

@ -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;")
}
)

View File

@ -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()
}
}

View File

@ -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: ")
)

View File

@ -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.")
)

View File

@ -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>" }
)

View File

@ -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()
}
}

View File

@ -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" }
)

View File

@ -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" }
)

View File

@ -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

View File

@ -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()
}
}

View File

@ -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")
)

View File

@ -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")
)

View File

@ -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")
)

View File

@ -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
)
)

View File

@ -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")
)

View File

@ -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
)
)

View File

@ -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
)
)

View File

@ -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)
}
}

View File

@ -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) }
)

View File

@ -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" }
)

View File

@ -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) }
)

View File

@ -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
)
)

View File

@ -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
)
)

View File

@ -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
}
}

View File

@ -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
)
)

View File

@ -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
"""
)
}
}

View File

@ -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) }
)

View File

@ -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"
}
}

View File

@ -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)
}
}
}

View File

@ -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")
)

View File

@ -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) }
)

View File

@ -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" }
)

View File

@ -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"
)
}
}
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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
)
)

View File

@ -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"}
)

View File

@ -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
}
}

View File

@ -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

View File

@ -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;")
}
)

View File

@ -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"
)
}
}
}

View File

@ -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;") }
)

View File

@ -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: ")
)

View File

@ -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."
),
)

View File

@ -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")
)

View File

@ -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")
}
)

View File

@ -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,
)
)

View File

@ -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=")
)

View File

@ -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"
)
}
}