feat(YouTube): Add Change form factor patch (#4217)

This commit is contained in:
LisoUseInAIKyrios
2024-12-27 10:48:14 +04:00
committed by GitHub
parent da4aeac42b
commit 644ac5baa6
18 changed files with 365 additions and 156 deletions

View File

@ -1101,6 +1101,10 @@ public final class app/revanced/patches/youtube/layout/buttons/overlay/HidePlaye
public static final fun getHidePlayerOverlayButtonsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/layout/formfactor/ChangeFormFactorPatchKt {
public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatchKt {
public static final fun getHideEndscreenCardsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
@ -1230,7 +1234,6 @@ public final class app/revanced/patches/youtube/layout/startupshortsreset/Disabl
}
public final class app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatchKt {
public static final field EXTENSION_CLASS_DESCRIPTOR Ljava/lang/String;
public static final fun getEnableTabletLayoutPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

View File

@ -0,0 +1,75 @@
package app.revanced.patches.youtube.layout.formfactor
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ChangeFormFactorPatch;"
@Suppress("unused")
val changeFormFactorPatch = bytecodePatch(
name = "Change form factor",
description = "Adds an option to change the UI appearance to a phone, tablet, or automotive device.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.youtube"(
"18.38.44",
"18.49.37",
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
),
)
execute {
addResources("youtube", "layout.formfactor.changeFormFactorPatch")
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
ListPreference(
"revanced_change_form_factor",
summaryKey = null,
)
)
createPlayerRequestBodyWithModelFingerprint.method.apply {
val formFactorEnumClass = formFactorEnumConstructorFingerprint.originalClassDef.type
val index = indexOfFirstInstructionOrThrow {
val reference = getReference<FieldReference>()
opcode == Opcode.IGET &&
reference?.definingClass == formFactorEnumClass &&
reference.type == "I"
}
val register = getInstruction<TwoRegisterInstruction>(index).registerA
addInstructions(
index + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getFormFactor(I)I
move-result v$register
"""
)
}
}
}

View File

@ -0,0 +1,49 @@
package app.revanced.patches.youtube.layout.formfactor
import app.revanced.patcher.fingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
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.FieldReference
internal val formFactorEnumConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
strings(
"UNKNOWN_FORM_FACTOR",
"SMALL_FORM_FACTOR",
"LARGE_FORM_FACTOR",
"AUTOMOTIVE_FORM_FACTOR"
)
}
internal val createPlayerRequestBodyWithModelFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters()
opcodes(Opcode.OR_INT_LIT16)
custom { method, _ ->
method.indexOfModelInstruction() >= 0 &&
method.indexOfReleaseInstruction() >= 0
}
}
private fun Method.indexOfModelInstruction() =
indexOfFirstInstruction {
val reference = getReference<FieldReference>()
reference?.definingClass == "Landroid/os/Build;" &&
reference.name == "MODEL" &&
reference.type == "Ljava/lang/String;"
}
internal fun Method.indexOfReleaseInstruction(): Int =
indexOfFirstInstruction {
val reference = getReference<FieldReference>()
reference?.definingClass == "Landroid/os/Build${'$'}VERSION;" &&
reference.name == "RELEASE" &&
reference.type == "Ljava/lang/String;"
}

View File

@ -1,66 +1,9 @@
package app.revanced.patches.youtube.layout.tablet
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.instructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.layout.formfactor.changeFormFactorPatch
const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/TabletLayoutPatch;"
val enableTabletLayoutPatch = bytecodePatch(
name = "Enable tablet layout",
description = "Adds an option to enable tablet layout.",
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.youtube"(
"18.38.44",
"18.49.37",
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
),
)
execute {
addResources("youtube", "layout.tablet.enableTabletLayoutPatch")
PreferenceScreen.GENERAL_LAYOUT.addPreferences(
SwitchPreference("revanced_tablet_layout"),
)
getFormFactorFingerprint.method.apply {
val returnIsLargeFormFactorIndex = instructions.lastIndex - 4
val returnIsLargeFormFactorLabel = getInstruction(returnIsLargeFormFactorIndex)
addInstructionsWithLabels(
0,
"""
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->getTabletLayoutEnabled()Z
move-result v0
if-nez v0, :is_large_form_factor
""",
ExternalLabel(
"is_large_form_factor",
returnIsLargeFormFactorLabel,
),
)
}
}
}
@Deprecated("Use 'Change form factor' instead.")
val enableTabletLayoutPatch = bytecodePatch {
dependsOn(changeFormFactorPatch)
}

View File

@ -1,25 +0,0 @@
package app.revanced.patches.youtube.layout.tablet
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val getFormFactorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("L")
parameters("Landroid/content/Context;", "Ljava/util/List;")
opcodes(
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.SGET_OBJECT,
Opcode.RETURN_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT,
)
strings("")
}

View File

@ -105,3 +105,15 @@ internal val pivotBarConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
strings("com.google.android.apps.youtube.app.endpoint.flags")
}
internal val imageEnumConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
strings("TAB_ACTIVITY_CAIRO")
}
internal val setEnumMapFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
literal {
ytFillBellId
}
}

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.misc.navigation
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.instructions
import app.revanced.patcher.patch.PatchException
@ -12,13 +13,16 @@ import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
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.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
@ -26,6 +30,8 @@ internal var imageOnlyTabResourceId = -1L
private set
internal var actionBarSearchResultsViewMicId = -1L
private set
internal var ytFillBellId = -1L
private set
private val navigationBarHookResourcePatch = resourcePatch {
dependsOn(resourceMappingPatch)
@ -33,6 +39,7 @@ private val navigationBarHookResourcePatch = resourcePatch {
execute {
imageOnlyTabResourceId = resourceMappings["layout", "image_only_tab"]
actionBarSearchResultsViewMicId = resourceMappings["layout", "action_bar_search_results_view_mic"]
ytFillBellId = resourceMappings["drawable", "yt_fill_bell_black_24"]
}
}
@ -144,6 +151,36 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
)
}
// Fix YT bug of notification tab missing the filled icon.
if (is_19_35_or_greater) {
val cairoNotificationEnumReference = with(imageEnumConstructorFingerprint) {
val stringIndex = stringMatches!!.first().index
val cairoNotificationEnumIndex = method.indexOfFirstInstructionOrThrow(stringIndex) {
opcode == Opcode.SPUT_OBJECT
}
method.getInstruction<ReferenceInstruction>(cairoNotificationEnumIndex).reference
}
setEnumMapFingerprint.method.apply {
val enumMapIndex = indexOfFirstInstructionReversedOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.definingClass == "Ljava/util/EnumMap;" &&
reference.name == "put" &&
reference.parameterTypes.firstOrNull() == "Ljava/lang/Enum;"
}
val instruction = getInstruction<FiveRegisterInstruction>(enumMapIndex)
addInstructions(
enumMapIndex + 1,
"""
sget-object v${instruction.registerD}, $cairoNotificationEnumReference
invoke-static { v${instruction.registerC}, v${instruction.registerD} }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
"""
)
}
}
}
}

View File

@ -8,7 +8,7 @@
<item>iOS TV</item>
</string-array>
<string-array name="revanced_spoof_video_streams_client_type_entry_values">
<!-- Enum names from extension -->
<!-- Extension enum names. -->
<item>ANDROID_VR</item>
<item>ANDROID_VR_NO_AUTH</item>
<item>ANDROID_UNPLUGGED</item>
@ -148,6 +148,21 @@
<item>17.33.42</item>
</string-array>
</patch>
<patch id="layout.formfactor.changeFormFactorPatch">
<string-array name="revanced_change_form_factor_entries">
<item>@string/revanced_change_form_factor_entry_1</item>
<item>@string/revanced_change_form_factor_entry_2</item>
<item>@string/revanced_change_form_factor_entry_3</item>
<item>@string/revanced_change_form_factor_entry_4</item>
</string-array>
<string-array name="revanced_change_form_factor_entry_values">
<!-- Extension enum names. -->
<item>DEFAULT</item>
<item>SMALL</item>
<item>LARGE</item>
<item>AUTOMOTIVE</item>
</string-array>
</patch>
<patch id="layout.player.fullscreen.exitFullscreenPatch">
<string-array name="revanced_exit_fullscreen_entries">
<item>@string/revanced_exit_fullscreen_entry_1</item>
@ -174,7 +189,7 @@
<item>@string/revanced_miniplayer_type_entry_6</item>
</string-array>
<string-array name="revanced_miniplayer_type_entry_values">
<!-- Enum names from the extension. -->
<!-- Extension enum names. -->
<item>DISABLED</item>
<item>DEFAULT</item>
<item>MINIMAL</item>
@ -192,7 +207,7 @@
<item>@string/revanced_miniplayer_type_entry_6</item>
</string-array>
<string-array name="revanced_miniplayer_type_legacy_entry_values">
<!-- Enum names from the extension. -->
<!-- Extension enum names. -->
<item>DEFAULT</item>
<item>MINIMAL</item>
<item>TABLET</item>
@ -221,7 +236,7 @@
<item>@string/revanced_change_start_page_entry_browse</item>
</string-array>
<string-array name="revanced_change_start_page_entry_values">
<!-- Enum names from extension -->
<!-- Extension enum names. -->
<item>DEFAULT</item>
<!-- Intent Action -->
<item>SEARCH</item>
@ -248,7 +263,7 @@
<item>@string/revanced_shorts_player_type_regular_player</item>
</string-array>
<string-array name="revanced_shorts_player_type_legacy_entry_values">
<!-- Enum names from extension -->
<!-- Extension enum names. -->
<item>SHORTS_PLAYER</item>
<item>REGULAR_PLAYER</item>
</string-array>
@ -272,7 +287,7 @@
<item>@string/revanced_alt_thumbnail_options_entry_4</item>
</string-array>
<string-array name="revanced_alt_thumbnail_options_entry_values">
<!-- Enum names from the extension -->
<!-- Extension enum names. -->
<item>ORIGINAL</item>
<item>DEARROW</item>
<item>DEARROW_STILL_IMAGES</item>

View File

@ -1029,6 +1029,23 @@ Ready to submit?"</string>
<string name="revanced_sb_about_api">sponsor.ajay.app</string>
<string name="revanced_sb_about_api_sum">Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms</string>
</patch>
<patch id="layout.formfactor.changeFormFactorPatch">
<string name="revanced_change_form_factor_title">Layout form factor</string>
<string name="revanced_change_form_factor_entry_1">Default</string>
<string name="revanced_change_form_factor_entry_2">Phone</string>
<string name="revanced_change_form_factor_entry_3">Tablet</string>
<string name="revanced_change_form_factor_entry_4">Automotive</string>
<string name="revanced_change_form_factor_user_dialog_message">"Changes include:
Tablet layout
• Community posts are hidden
Automotive layout
• Watch history menu is hidden
• Explore tab is restored
• Shorts open in the regular player
• Feed is organized by topics and channel"</string>
</patch>
<patch id="layout.spoofappversion.spoofAppVersionPatch">
<string name="revanced_spoof_app_version_title">Spoof app version</string>
<string name="revanced_spoof_app_version_summary_on">Version spoofed</string>
@ -1086,12 +1103,6 @@ If later turned off, it is recommended to clear the app data to prevent UI bugs.
<string name="revanced_shorts_autoplay_background_summary_on">Shorts background play will autoplay</string>
<string name="revanced_shorts_autoplay_background_summary_off">Shorts background play will repeat</string>
</patch>
<patch id="layout.tablet.enableTabletLayoutPatch">
<string name="revanced_tablet_layout_title">Enable tablet layout</string>
<string name="revanced_tablet_layout_summary_on">Tablet layout is enabled</string>
<string name="revanced_tablet_layout_summary_off">Tablet layout is disabled</string>
<string name="revanced_tablet_layout_user_dialog_message">Community posts do not show up on tablet layouts</string>
</patch>x
<patch id="layout.miniplayer.miniplayerPatch">
<string name="revanced_miniplayer_screen_title">Miniplayer</string>
<string name="revanced_miniplayer_screen_summary">Change the style of the in app minimized player</string>