feat(YouTube): add support versions 19.19.39 ~ 19.20.34

This commit is contained in:
inotia00
2024-05-26 17:19:44 +09:00
parent 0b9ea6ac26
commit 029219a4cc
24 changed files with 443 additions and 109 deletions

View File

@ -16,20 +16,21 @@ import app.revanced.patches.youtube.player.buttons.fingerprints.YouTubeControlsO
import app.revanced.patches.youtube.utils.castbutton.CastButtonPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.fingerprints.LayoutConstructorFingerprint
import app.revanced.patches.youtube.utils.fix.fullscreen.FullscreenButtonViewStubPatch
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.AutoNavToggle
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FullScreenButton
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.PlayerCollapseButton
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.TitleAnchor
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexWithReference
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
@Suppress("unused")
@ -38,6 +39,7 @@ object PlayerButtonsPatch : BaseBytecodePatch(
description = "Adds an option to hide buttons in the video player.",
dependencies = setOf(
CastButtonPatch::class,
FullscreenButtonViewStubPatch::class,
SettingsPatch::class,
SharedResourceIdPatch::class
),
@ -147,16 +149,22 @@ object PlayerButtonsPatch : BaseBytecodePatch(
FullScreenButtonFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val viewIndex = getTargetIndexWithReference("Landroid/widget/ImageView;->getResources()Landroid/content/res/Resources;")
val viewRegister = getInstruction<FiveRegisterInstruction>(viewIndex).registerC
val buttonCalls = implementation!!.instructions.withIndex()
.filter { instruction ->
(instruction.value as? WideLiteralInstruction)?.wideLiteral == FullScreenButton
}
val constIndex = buttonCalls.elementAt(buttonCalls.size - 1).index
val castIndex = getTargetIndex(constIndex, Opcode.CHECK_CAST)
val insertIndex = castIndex + 1
val insertRegister = getInstruction<OneRegisterInstruction>(castIndex).registerA
addInstructionsWithLabels(
viewIndex, """
invoke-static {v$viewRegister}, $PLAYER_CLASS_DESCRIPTOR->hideFullscreenButton(Landroid/widget/ImageView;)Landroid/widget/ImageView;
move-result-object v$viewRegister
if-nez v$viewRegister, :show
insertIndex, """
invoke-static {v$insertRegister}, $PLAYER_CLASS_DESCRIPTOR->hideFullscreenButton(Landroid/widget/ImageView;)Landroid/widget/ImageView;
move-result-object v$insertRegister
if-nez v$insertRegister, :show
return-void
""", ExternalLabel("show", getInstruction(viewIndex))
""", ExternalLabel("show", getInstruction(insertIndex))
)
}
}

View File

@ -2,6 +2,7 @@ package app.revanced.patches.youtube.player.buttons.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.CfFullscreenButton
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FadeDurationFast
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.FullScreenButton
import app.revanced.util.containsWideLiteralInstructionIndex
@ -11,8 +12,11 @@ internal object FullScreenButtonFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/View;"),
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionIndex(FadeDurationFast)
&& methodDef.containsWideLiteralInstructionIndex(FullScreenButton)
customFingerprint = handler@{ methodDef, _ ->
if (!methodDef.containsWideLiteralInstructionIndex(FullScreenButton))
return@handler false
methodDef.containsWideLiteralInstructionIndex(FadeDurationFast) // YouTube 18.29.38 ~ YouTube 19.18.41
|| methodDef.containsWideLiteralInstructionIndex(CfFullscreenButton) // YouTube 19.19.39 ~
},
)

View File

@ -20,14 +20,12 @@ import app.revanced.patches.youtube.player.components.fingerprints.InfoCardsInco
import app.revanced.patches.youtube.player.components.fingerprints.LayoutCircleFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.LayoutIconFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.LayoutVideoFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.RestoreSlideToSeekBehaviorFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.SeekEduContainerFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.SpeedOverlayFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.SpeedOverlayValueFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.SuggestedActionsFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.TouchAreaOnClickListenerFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.WatermarkFingerprint
import app.revanced.patches.youtube.player.components.fingerprints.WatermarkParentFingerprint
import app.revanced.patches.youtube.player.speedoverlay.SpeedOverlayPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.controlsoverlay.ControlsOverlayConfigPatch
import app.revanced.patches.youtube.utils.fingerprints.YouTubeControlsOverlayFingerprint
@ -44,7 +42,6 @@ import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexReversed
import app.revanced.util.getTargetIndexWithMethodReferenceName
import app.revanced.util.getWideLiteralInstructionIndex
import app.revanced.util.literalInstructionBooleanHook
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -64,6 +61,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
PlayerTypeHookPatch::class,
SettingsPatch::class,
SharedResourceIdPatch::class,
SpeedOverlayPatch::class,
SuggestedVideoEndScreenPatch::class
),
compatiblePackages = COMPATIBLE_PACKAGE,
@ -75,10 +73,7 @@ object PlayerComponentsPatch : BaseBytecodePatch(
LayoutCircleFingerprint,
LayoutIconFingerprint,
LayoutVideoFingerprint,
RestoreSlideToSeekBehaviorFingerprint,
SeekEduContainerFingerprint,
SpeedOverlayFingerprint,
SpeedOverlayValueFingerprint,
SuggestedActionsFingerprint,
TouchAreaOnClickListenerFingerprint,
WatermarkParentFingerprint,
@ -131,34 +126,6 @@ object PlayerComponentsPatch : BaseBytecodePatch(
// endregion
// region patch for disable speed overlay and speed overlay value
mapOf(
RestoreSlideToSeekBehaviorFingerprint to 45411329,
SpeedOverlayFingerprint to 45411330
).forEach { (fingerprint, literal) ->
fingerprint.literalInstructionBooleanHook(
literal,
"$PLAYER_CLASS_DESCRIPTOR->disableSpeedOverlay(Z)Z"
)
}
SpeedOverlayValueFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val index = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(index).registerA
addInstructions(
index + 1, """
invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$register
"""
)
}
}
// endregion
// region patch for hide channel watermark
WatermarkFingerprint.resolve(

View File

@ -16,6 +16,7 @@ import app.revanced.patches.youtube.player.flyoutmenu.toggle.fingerprints.Stable
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.getStringInstructionIndex
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexReversed
@ -26,6 +27,8 @@ import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Suppress("unused")
object ChangeTogglePatch : BaseBytecodePatch(
@ -123,6 +126,12 @@ object ChangeTogglePatch : BaseBytecodePatch(
CinematicLightingFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val iGetIndex = indexOfFirstInstruction {
opcode == Opcode.IGET
&& getReference<FieldReference>()?.definingClass == definingClass
}
val classRegister = getInstruction<TwoRegisterInstruction>(iGetIndex).registerB
val stringIndex = getStringInstructionIndex("menu_item_cinematic_lighting")
val checkCastIndex = getTargetIndexReversed(stringIndex, Opcode.CHECK_CAST)
@ -158,7 +167,7 @@ object ChangeTogglePatch : BaseBytecodePatch(
invoke-static {v$freeRegisterE}, $PLAYER_CLASS_DESCRIPTOR->getToggleString(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$freeRegisterE
:set_string
iget-object v$freeRegisterC, p0, $iGetObjectPrimaryReference
iget-object v$freeRegisterC, v$classRegister, $iGetObjectPrimaryReference
check-cast v$freeRegisterC, $checkCastReference
iget-object v$freeRegisterC, v$freeRegisterC, $iGetObjectSecondaryReference
const-string v$freeRegisterD, "menu_item_cinematic_lighting"

View File

@ -0,0 +1,224 @@
package app.revanced.patches.youtube.player.speedoverlay
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.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.HorizontalTouchOffsetConstructorFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.NextGenWatchLayoutFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.RestoreSlideToSeekBehaviorFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SlideToSeekMotionEventFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayTextValueFingerprint
import app.revanced.patches.youtube.player.speedoverlay.fingerprints.SpeedOverlayValueFingerprint
import app.revanced.patches.youtube.utils.integrations.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.getReference
import app.revanced.util.getTargetIndex
import app.revanced.util.getTargetIndexReversed
import app.revanced.util.getTargetIndexWithMethodReferenceName
import app.revanced.util.getTargetIndexWithMethodReferenceNameReversed
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.literalInstructionBooleanHook
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Patch(dependencies = [SharedResourceIdPatch::class])
object SpeedOverlayPatch : BytecodePatch(
setOf(
HorizontalTouchOffsetConstructorFingerprint,
NextGenWatchLayoutFingerprint,
RestoreSlideToSeekBehaviorFingerprint,
SpeedOverlayFingerprint,
SpeedOverlayTextValueFingerprint,
SpeedOverlayValueFingerprint,
)
) {
override fun execute(context: BytecodeContext) {
val restoreSlideToSeekBehaviorFingerprintResult = RestoreSlideToSeekBehaviorFingerprint.result
val speedOverlayFingerprintResult = SpeedOverlayFingerprint.result
val speedOverlayValueFingerprintResult = SpeedOverlayValueFingerprint.result
val resolvable =
restoreSlideToSeekBehaviorFingerprintResult != null
&& speedOverlayFingerprintResult != null
&& speedOverlayValueFingerprintResult != null
if (resolvable) {
// Legacy method.
// Used on YouTube 18.29.38 ~ YouTube 19.17.41
// region patch for disable speed overlay
mapOf(
RestoreSlideToSeekBehaviorFingerprint to 45411329,
SpeedOverlayFingerprint to 45411330
).forEach { (fingerprint, literal) ->
fingerprint.result!!.let {
fingerprint.literalInstructionBooleanHook(
literal,
"$PLAYER_CLASS_DESCRIPTOR->disableSpeedOverlay(Z)Z"
)
}
}
// endregion
// region patch for custom speed overlay value
speedOverlayValueFingerprintResult!!.let {
it.mutableMethod.apply {
val index = it.scanResult.patternScanResult!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(index).registerA
addInstructions(
index + 1, """
invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$register
"""
)
}
}
// endregion
} else {
// New method.
// Used on YouTube 19.18.41~
NextGenWatchLayoutFingerprint.resultOrThrow().mutableMethod.apply {
val booleanValueIndex = getTargetIndexWithMethodReferenceName("booleanValue")
val insertIndex = findIGetIndex(booleanValueIndex - 10, booleanValueIndex)
val insertInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
val insertReference = getInstruction<ReferenceInstruction>(insertIndex).reference
addInstruction(
insertIndex + 1,
"iget-object v${insertInstruction.registerA}, v${insertInstruction.registerB}, $insertReference"
)
val jumpIndex = findIGetIndex(booleanValueIndex, booleanValueIndex + 10)
hook(insertIndex + 1, insertInstruction.registerA, jumpIndex)
}
SlideToSeekMotionEventFingerprint.resolve(
context,
HorizontalTouchOffsetConstructorFingerprint.resultOrThrow().classDef
)
SlideToSeekMotionEventFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val scanResult = it.scanResult.patternScanResult!!
val slideToSeekBooleanIndex = scanResult.startIndex + 1
slideToSeekBooleanMethod = getWalkerMethod(context, slideToSeekBooleanIndex)
val jumpIndex = scanResult.endIndex + 1
val insertIndex = scanResult.endIndex - 1
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
hook(insertIndex, insertRegister, jumpIndex)
}
}
slideToSeekBooleanMethod.apply {
var insertIndex = getTargetIndex(Opcode.IGET_OBJECT)
var insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
var jumpIndex = getTargetIndexReversed(Opcode.INVOKE_VIRTUAL)
hook(insertIndex, insertRegister, jumpIndex)
val constructorMethod =
context.findClass(definingClass)?.mutableClass
?.methods?.find { method -> method.name == "<init>" }
?: throw PatchException("Could not find constructor method")
constructorMethod.apply {
val syntheticIndex = getTargetIndexReversed(Opcode.NEW_INSTANCE)
val syntheticClass = getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
val syntheticMethod =
context.findClass(syntheticClass)?.mutableClass
?.methods?.find { method -> method.name == "run" }
?: throw PatchException("Could not find synthetic method")
syntheticMethod.apply {
val speedOverlayValueIndex =
indexOfFirstInstruction { (this as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
val speedOverlayValueRegister =
getInstruction<OneRegisterInstruction>(speedOverlayValueIndex).registerA
addInstructions(
speedOverlayValueIndex + 1, """
invoke-static {v$speedOverlayValueRegister}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue(F)F
move-result v$speedOverlayValueRegister
"""
)
insertIndex = getTargetIndexWithMethodReferenceNameReversed(speedOverlayValueIndex, "removeCallbacks") + 1
insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex - 1).registerC
jumpIndex = getTargetIndex(speedOverlayValueIndex, Opcode.RETURN_VOID) + 1
hook(insertIndex, insertRegister, jumpIndex)
}
}
}
SpeedOverlayTextValueFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.startIndex
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue()D
move-result-wide v$targetRegister
"""
)
}
}
}
}
private lateinit var slideToSeekBooleanMethod: MutableMethod
// restore slide to seek
private fun MutableMethod.hook(
insertIndex: Int,
insertRegister: Int,
jumpIndex: Int
) {
addInstructionsWithLabels(
insertIndex,
"""
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->disableSpeedOverlay()Z
move-result v$insertRegister
if-eqz v$insertRegister, :disable
""", ExternalLabel("disable", getInstruction(jumpIndex))
)
}
private fun MutableMethod.findIGetIndex(
startIndex: Int,
endIndex: Int
): Int = implementation!!.instructions.let { instruction ->
startIndex + instruction.subList(startIndex, endIndex).indexOfFirst {
it.opcode == Opcode.IGET_OBJECT
&& it.getReference<FieldReference>()?.definingClass == definingClass
}
}
}

View File

@ -0,0 +1,11 @@
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patches.youtube.utils.resourceid.SharedResourceIdPatch.SeekEasyHorizontalTouchOffsetToStartScrubbing
import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object HorizontalTouchOffsetConstructorFingerprint : LiteralValueFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
literalSupplier = { SeekEasyHorizontalTouchOffsetToStartScrubbing }
)

View File

@ -0,0 +1,18 @@
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.containsMethodReferenceNameInstructionIndex
import com.android.tools.smali.dexlib2.AccessFlags
internal object NextGenWatchLayoutFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
customFingerprint = handler@{ methodDef, _ ->
if (methodDef.definingClass != "Lcom/google/android/apps/youtube/app/watch/nextgenwatch/ui/NextGenWatchLayout;")
return@handler false
methodDef.containsMethodReferenceNameInstructionIndex("booleanValue")
}
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.player.components.fingerprints
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.Opcode

View File

@ -0,0 +1,20 @@
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object SlideToSeekMotionEventFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/View;", "Landroid/view/MotionEvent;"),
opcodes = listOf(
Opcode.SUB_FLOAT_2ADDR,
Opcode.INVOKE_VIRTUAL, // SlideToSeek Boolean method
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT, // insert index
Opcode.INVOKE_VIRTUAL
)
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.player.components.fingerprints
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.Opcode

View File

@ -0,0 +1,14 @@
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.util.fingerprint.ReferenceFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object SpeedOverlayTextValueFingerprint : ReferenceFingerprint(
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = emptyList(),
opcodes = listOf(Opcode.CONST_WIDE_HIGH16),
reference = { "Ljava/math/BigDecimal;->signum()I" }
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.player.components.fingerprints
package app.revanced.patches.youtube.player.speedoverlay.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.util.fingerprint.LiteralValueFingerprint