feat(YouTube): Add Change form factor, Remove Change layout patch

This commit is contained in:
inotia00
2025-03-14 18:37:56 +09:00
parent 1b3ebe1a58
commit 86e5c1b45c
22 changed files with 579 additions and 212 deletions

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.general.layoutswitch
package app.revanced.patches.youtube.general.formfactor
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
@ -6,30 +6,37 @@ import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
import app.revanced.patches.youtube.utils.patch.PatchList.CHANGE_LAYOUT
import app.revanced.patches.youtube.utils.navigation.hookNavigationButtonCreated
import app.revanced.patches.youtube.utils.navigation.navigationBarHookPatch
import app.revanced.patches.youtube.utils.patch.PatchList.CHANGE_FORM_FACTOR
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
import app.revanced.patches.youtube.utils.settings.settingsPatch
import app.revanced.util.fingerprint.definingClassOrThrow
import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"$GENERAL_PATH/LayoutSwitchPatch;"
"$GENERAL_PATH/ChangeFormFactorPatch;"
@Suppress("unused")
val layoutSwitchPatch = bytecodePatch(
CHANGE_LAYOUT.title,
CHANGE_LAYOUT.summary,
val changeFormFactorPatch = bytecodePatch(
CHANGE_FORM_FACTOR.title,
CHANGE_FORM_FACTOR.summary,
) {
compatibleWith(COMPATIBLE_PACKAGE)
dependsOn(settingsPatch)
dependsOn(
settingsPatch,
playerTypeHookPatch,
navigationBarHookPatch,
)
execute {
@ -53,27 +60,31 @@ val layoutSwitchPatch = bytecodePatch(
)
}
layoutSwitchFingerprint.methodOrThrow().apply {
val index = indexOfFirstInstructionReversedOrThrow(Opcode.IF_NEZ)
val register = getInstruction<OneRegisterInstruction>(index).registerA
widthDpUIFingerprint.matchOrThrow().let {
it.method.apply {
val index = it.patternMatch!!.startIndex
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index, """
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->getWidthDp(I)I
move-result v$register
"""
)
addInstructions(
index, """
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->getWidthDp(I)I
move-result v$register
"""
)
}
}
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
// region add settings
addPreference(
arrayOf(
"PREFERENCE_SCREEN: GENERAL",
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS",
"SETTINGS: CHANGE_LAYOUT"
"SETTINGS: CHANGE_FORM_FACTOR"
),
CHANGE_LAYOUT
CHANGE_FORM_FACTOR
)
// endregion

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.general.layoutswitch
package app.revanced.patches.youtube.general.formfactor
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or
@ -11,20 +11,16 @@ internal val formFactorEnumConstructorFingerprint = legacyFingerprint(
strings = listOf(
"UNKNOWN_FORM_FACTOR",
"SMALL_FORM_FACTOR",
"LARGE_FORM_FACTOR"
"LARGE_FORM_FACTOR",
"AUTOMOTIVE_FORM_FACTOR",
)
)
internal val layoutSwitchFingerprint = legacyFingerprint(
name = "layoutSwitchFingerprint",
internal val widthDpUIFingerprint = legacyFingerprint(
name = "widthDpUIFingerprint",
returnType = "I",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
Opcode.CONST_4,
Opcode.RETURN,
@ -41,6 +37,11 @@ internal val layoutSwitchFingerprint = legacyFingerprint(
Opcode.CONST_4,
Opcode.RETURN,
Opcode.CONST_4,
Opcode.RETURN
Opcode.RETURN,
),
literals = listOf(
480L,
600L,
720L
)
)

View File

@ -109,8 +109,7 @@ val navigationBarHookPatch = bytecodePatch(
hookNavigationButtonCreated = { extensionClassDescriptor ->
navigationBarHookCallbackFingerprint.methodOrThrow().addInstruction(
0,
"invoke-static { p0, p1 }, " +
"$extensionClassDescriptor->navigationTabCreated" +
"invoke-static { p0, p1 }, $extensionClassDescriptor->navigationTabCreated" +
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
)
}

View File

@ -21,9 +21,9 @@ internal enum class PatchList(
"Bypass URL redirects",
"Adds an option to bypass URL redirects and open the original URL directly."
),
CHANGE_LAYOUT(
"Change layout",
"Adds an option to change the dp in order to use a tablet or phone layout."
CHANGE_FORM_FACTOR(
"Change form factor",
"Adds an option to change the UI appearance to a phone, tablet, or automotive device."
),
CHANGE_LIVE_RING_CLICK_ACTION(
"Change live ring click action",

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.utils.playertype
import app.revanced.patches.youtube.utils.resourceid.reelWatchPlayer
import app.revanced.patches.youtube.utils.resourceid.toolbarContainerId
import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
@ -9,6 +10,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
internal val browseIdClassFingerprint = legacyFingerprint(
name = "browseIdClassFingerprint",
@ -61,6 +63,34 @@ internal val searchQueryClassFingerprint = legacyFingerprint(
}
)
internal val toolbarLayoutFingerprint = legacyFingerprint(
name = "toolbarLayoutFingerprint",
literals = listOf(toolbarContainerId),
customFingerprint = { method, _ ->
method.name == "<init>" &&
indexOfMainCollapsingToolbarLayoutInstruction(method) >= 0
}
)
internal fun indexOfMainCollapsingToolbarLayoutInstruction(method: Method) =
method.indexOfFirstInstruction {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == "Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;"
}
/**
* Matches to https://android.googlesource.com/platform/frameworks/support/+/9eee6ba/v7/appcompat/src/android/support/v7/widget/Toolbar.java#963
*/
internal val appCompatToolbarBackButtonFingerprint = legacyFingerprint(
name = "appCompatToolbarBackButtonFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Landroid/graphics/drawable/Drawable;",
parameters = emptyList(),
customFingerprint = { _, classDef ->
classDef.type == "Landroid/support/v7/widget/Toolbar;"
},
)
internal val videoStateFingerprint = legacyFingerprint(
name = "videoStateFingerprint",
returnType = "V",

View File

@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.shared.litho.addLithoFilter
import app.revanced.patches.shared.litho.lithoFilterPatch
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
@ -21,10 +22,13 @@ import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
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.reference.FieldReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
private const val EXTENSION_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR =
"$UTILS_PATH/PlayerTypeHookPatch;"
@ -32,6 +36,9 @@ private const val EXTENSION_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR =
private const val EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR =
"$SHARED_PATH/RootView;"
private const val EXTENSION_ROOT_VIEW_TOOLBAR_INTERFACE =
"$SHARED_PATH/RootView${'$'}AppCompatToolbarPatchInterface;"
private const val FILTER_CLASS_DESCRIPTOR =
"$COMPONENTS_PATH/RelatedVideoFilter;"
@ -165,6 +172,53 @@ val playerTypeHookPatch = bytecodePatch(
// endregion
// region patch for hook back button visibility
toolbarLayoutFingerprint.methodOrThrow().apply {
val index = indexOfMainCollapsingToolbarLayoutInstruction(this)
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstruction(
index + 1,
"invoke-static { v$register }, $EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR->setToolbar(Landroid/widget/FrameLayout;)V"
)
}
// Add interface for extensions code to call obfuscated methods.
appCompatToolbarBackButtonFingerprint.matchOrThrow().let {
it.classDef.apply {
interfaces.add(EXTENSION_ROOT_VIEW_TOOLBAR_INTERFACE)
val definingClass = type
val obfuscatedMethodName = it.originalMethod.name
val returnType = "Landroid/graphics/drawable/Drawable;"
methods.add(
ImmutableMethod(
definingClass,
"patch_getToolbarIcon",
listOf(),
returnType,
AccessFlags.PUBLIC.value or AccessFlags.FINAL.value,
null,
null,
MutableMethodImplementation(2),
).toMutable().apply {
addInstructions(
0,
"""
invoke-virtual { p0 }, $definingClass->$obfuscatedMethodName()$returnType
move-result-object v0
return-object v0
"""
)
}
)
}
}
// endregion
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
}
}

View File

@ -213,6 +213,8 @@ var tapBloomView = -1L
private set
var titleAnchor = -1L
private set
var toolbarContainerId = -1L
private set
var toolTipContentView = -1L
private set
var totalTime = -1L
@ -656,6 +658,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ID,
"title_anchor"
]
toolbarContainerId = resourceMappings[
ID,
"toolbar_container"
]
toolTipContentView = resourceMappings[
LAYOUT,
"tooltip_content_view"