From 22419fd9d53bd2234283423a8e9fec30b1fff3fc Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:02:28 +0900 Subject: [PATCH] feat(YouTube): Support version `19.44.39` --- .../sponsorblock/SponsorBlockSettings.java | 1 + .../extension/music/utils/ExtendedUtils.java | 1 - .../youtube/patches/player/PlayerPatch.java | 42 ++++++ .../patches/shorts/CustomActionsPatch.java | 31 +++-- .../sponsorblock/SponsorBlockSettings.java | 1 + .../youtube/general/toolbar/Fingerprints.kt | 26 +--- .../general/toolbar/ToolBarComponentsPatch.kt | 4 +- .../actionbuttons/ShortsActionButtonsPatch.kt | 131 +++++++++++++----- .../ambientmode/AmbientModeSwitchPatch.kt | 37 ++++- .../player/ambientmode/Fingerprints.kt | 15 +- .../player/buttons/PlayerButtonsPatch.kt | 50 +++++-- .../youtube/player/components/Fingerprints.kt | 12 +- .../components/PlayerComponentsPatch.kt | 34 ++--- .../DescriptionComponentsPatch.kt | 8 +- .../fullscreen/FullscreenComponentsPatch.kt | 5 +- .../overlaybuttons/OverlayButtonsPatch.kt | 107 +++++++------- .../shorts/components/ShortsComponentPatch.kt | 8 +- .../patches/youtube/utils/Fingerprints.kt | 7 +- .../youtube/utils/compatibility/Constants.kt | 2 +- .../youtube/utils/fix/cairo/Fingerprints.kt | 4 +- .../utils/recyclerview/Fingerprints.kt | 15 +- ...ch.kt => RecyclerViewTreeObserverPatch.kt} | 23 ++- .../utils/resourceid/SharedResourceIdPatch.kt | 18 ++- .../video/playback/VideoPlaybackPatch.kt | 10 +- 24 files changed, 382 insertions(+), 210 deletions(-) rename patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/{BottomSheetRecyclerViewPatch.kt => RecyclerViewTreeObserverPatch.kt} (69%) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/sponsorblock/SponsorBlockSettings.java b/extensions/shared/src/main/java/app/revanced/extension/music/sponsorblock/SponsorBlockSettings.java index 2973297be..eef25d14d 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/sponsorblock/SponsorBlockSettings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/sponsorblock/SponsorBlockSettings.java @@ -18,6 +18,7 @@ public class SponsorBlockSettings { public void settingsImported(@Nullable Context context) { SegmentCategory.loadAllCategoriesFromSettings(); } + @Override public void settingsExported(@Nullable Context context) { } diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/utils/ExtendedUtils.java b/extensions/shared/src/main/java/app/revanced/extension/music/utils/ExtendedUtils.java index 91a7a660d..5de71744e 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/utils/ExtendedUtils.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/utils/ExtendedUtils.java @@ -2,7 +2,6 @@ import android.app.AlertDialog; import android.content.Context; -import android.util.TypedValue; import android.view.ViewGroup; import android.widget.FrameLayout; diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java index 8b9c2de35..e7fd135d1 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java @@ -74,6 +74,11 @@ public class PlayerPatch { // region [Ambient mode control] patch + /** + * Constant found in: androidx.window.embedding.DividerAttributes + */ + private static final int DIVIDER_ATTRIBUTES_COLOR_SYSTEM_DEFAULT = -16777216; + public static boolean bypassAmbientModeRestrictions(boolean original) { return (!Settings.BYPASS_AMBIENT_MODE_RESTRICTIONS.get() && original) || Settings.DISABLE_AMBIENT_MODE.get(); } @@ -82,6 +87,14 @@ public static boolean disableAmbientModeInFullscreen() { return !Settings.DISABLE_AMBIENT_MODE_IN_FULLSCREEN.get(); } + public static int getFullScreenBackgroundColor(int originalColor) { + if (Settings.DISABLE_AMBIENT_MODE_IN_FULLSCREEN.get()) { + return DIVIDER_ATTRIBUTES_COLOR_SYSTEM_DEFAULT; + } + + return originalColor; + } + // endregion // region [Change player flyout menu toggles] patch @@ -424,6 +437,35 @@ public static boolean hidePreviousNextButton(boolean previousOrNextButtonVisible return !Settings.HIDE_PLAYER_PREVIOUS_NEXT_BUTTON.get() && previousOrNextButtonVisible; } + private static final int playerControlPreviousButtonTouchAreaId = + ResourceUtils.getIdIdentifier("player_control_previous_button_touch_area"); + private static final int playerControlNextButtonTouchAreaId = + ResourceUtils.getIdIdentifier("player_control_next_button_touch_area"); + + public static void hidePreviousNextButtons(View parentView) { + if (!Settings.HIDE_PLAYER_PREVIOUS_NEXT_BUTTON.get()) { + return; + } + + // Must use a deferred call to main thread to hide the button. + // Otherwise the layout crashes if set to hidden now. + Utils.runOnMainThread(() -> { + hideView(parentView, playerControlPreviousButtonTouchAreaId); + hideView(parentView, playerControlNextButtonTouchAreaId); + }); + } + + private static void hideView(View parentView, int resourceId) { + View nextPreviousButton = parentView.findViewById(resourceId); + + if (nextPreviousButton == null) { + Logger.printException(() -> "Could not find player previous / next button"); + return; + } + + Utils.hideViewByRemovingFromParentUnderCondition(true, nextPreviousButton); + } + public static boolean hideMusicButton() { return Settings.HIDE_PLAYER_YOUTUBE_MUSIC_BUTTON.get(); } diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/shorts/CustomActionsPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/shorts/CustomActionsPatch.java index 462b0239f..4bf010129 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/shorts/CustomActionsPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/shorts/CustomActionsPatch.java @@ -1,5 +1,10 @@ package app.revanced.extension.youtube.patches.shorts; +import static app.revanced.extension.shared.utils.ResourceUtils.getString; +import static app.revanced.extension.shared.utils.Utils.dpToPx; +import static app.revanced.extension.youtube.patches.components.ShortsCustomActionsFilter.isShortsFlyoutMenuVisible; +import static app.revanced.extension.youtube.utils.ExtendedUtils.isSpoofingToLessThan; + import android.app.AlertDialog; import android.content.Context; import android.graphics.ColorFilter; @@ -10,13 +15,26 @@ import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.StateListDrawable; import android.support.v7.widget.RecyclerView; -import android.view.*; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + +import org.apache.commons.lang3.StringUtils; + +import java.lang.ref.WeakReference; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + import app.revanced.extension.shared.settings.BooleanSetting; import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.ResourceUtils; @@ -26,17 +44,6 @@ import app.revanced.extension.youtube.shared.ShortsPlayerState; import app.revanced.extension.youtube.utils.ThemeUtils; import app.revanced.extension.youtube.utils.VideoUtils; -import org.apache.commons.lang3.StringUtils; - -import java.lang.ref.WeakReference; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; - -import static app.revanced.extension.shared.utils.ResourceUtils.getString; -import static app.revanced.extension.shared.utils.Utils.dpToPx; -import static app.revanced.extension.youtube.patches.components.ShortsCustomActionsFilter.isShortsFlyoutMenuVisible; -import static app.revanced.extension.youtube.utils.ExtendedUtils.isSpoofingToLessThan; @SuppressWarnings("unused") public final class CustomActionsPatch { diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java index 7423ebdf1..d4228f3ec 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java @@ -34,6 +34,7 @@ public void settingsImported(@Nullable Context context) { SegmentCategory.loadAllCategoriesFromSettings(); SponsorBlockSettingsPreference.updateSegmentCategories(); } + @Override public void settingsExported(@Nullable Context context) { showExportWarningIfNeeded(context); diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/Fingerprints.kt index 00d8842c2..00ac1b22f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/Fingerprints.kt @@ -22,11 +22,11 @@ internal val actionBarRingoBackgroundFingerprint = legacyFingerprint( returnType = "Landroid/view/View;", literals = listOf(actionBarRingoBackground), customFingerprint = { method, _ -> - indexOfStaticInstruction(method) >= 0 + indexOfActionBarRingoBackgroundTabletInstruction(method) >= 0 } ) -internal fun indexOfStaticInstruction(method: Method) = +internal fun indexOfActionBarRingoBackgroundTabletInstruction(method: Method) = method.indexOfFirstInstruction { val reference = getReference() opcode == Opcode.INVOKE_STATIC && @@ -54,7 +54,7 @@ internal val actionBarRingoTextFingerprint = legacyFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, customFingerprint = { method, _ -> indexOfStartDelayInstruction(method) >= 0 && - indexOfStaticInstructions(method) >= 0 + indexOfActionBarRingoTextTabletInstructions(method) >= 0 } ) @@ -64,7 +64,7 @@ internal fun indexOfStartDelayInstruction(method: Method) = getReference()?.name == "setStartDelay" } -internal fun indexOfStaticInstructions(method: Method) = +internal fun indexOfActionBarRingoTextTabletInstructions(method: Method) = method.indexOfFirstInstructionReversed(indexOfStartDelayInstruction(method)) { val reference = getReference() opcode == Opcode.INVOKE_STATIC && @@ -175,24 +175,6 @@ internal val setActionBarRingoFingerprint = legacyFingerprint( literals = listOf(actionBarRingo), ) -internal val setWordMarkHeaderFingerprint = legacyFingerprint( - name = "setWordMarkHeaderFingerprint", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - returnType = "V", - parameters = listOf("Landroid/widget/ImageView;"), - opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.IGET_BOOLEAN, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.CONST, - Opcode.INVOKE_STATIC, - ) -) - @Suppress("SpellCheckingInspection") internal val yoodlesImageViewFingerprint = legacyFingerprint( name = "yoodlesImageViewFingerprint", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt index 5e6a78868..1b24b1bf8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt @@ -169,7 +169,7 @@ val toolBarComponentsPatch = bytecodePatch( "invoke-static {v$viewRegister}, $GENERAL_CLASS_DESCRIPTOR->setWideSearchBarLayout(Landroid/view/View;)V" ) - val targetIndex = indexOfStaticInstruction(this) + 1 + val targetIndex = indexOfActionBarRingoBackgroundTabletInstruction(this) + 1 val targetRegister = getInstruction(targetIndex).registerA injectSearchBarHook( @@ -180,7 +180,7 @@ val toolBarComponentsPatch = bytecodePatch( } actionBarRingoTextFingerprint.methodOrThrow(actionBarRingoBackgroundFingerprint).apply { - val targetIndex = indexOfStaticInstruction(this) + 1 + val targetIndex = indexOfActionBarRingoTextTabletInstructions(this) + 1 val targetRegister = getInstruction(targetIndex).registerA injectSearchBarHook( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt index 1f1dac491..eea71b603 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/layout/actionbuttons/ShortsActionButtonsPatch.kt @@ -4,15 +4,30 @@ import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.stringOption import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_SHORTS_ACTION_BUTTONS +import app.revanced.patches.youtube.utils.playservice.is_19_36_or_greater +import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.util.ResourceGroup import app.revanced.util.copyResources +import app.revanced.util.inputStreamFromBundledResourceOrThrow import app.revanced.util.lowerCaseOrThrow +import java.nio.file.Files +import java.nio.file.StandardCopyOption private const val DEFAULT_ICON = "cairo" private const val YOUTUBE_ICON = "youtube" +private val sizeArray = arrayOf( + "xxxhdpi", + "xxhdpi", + "xhdpi", + "hdpi", + "mdpi" +) + +private val drawableDirectories = sizeArray.map { "drawable-$it" } + @Suppress("unused") val shortsActionButtonsPatch = resourcePatch( CUSTOM_SHORTS_ACTION_BUTTONS.title, @@ -20,9 +35,12 @@ val shortsActionButtonsPatch = resourcePatch( ) { compatibleWith(COMPATIBLE_PACKAGE) - dependsOn(settingsPatch) + dependsOn( + settingsPatch, + versionCheckPatch + ) - val iconType = stringOption( + val iconTypeOption = stringOption( key = "iconType", default = DEFAULT_ICON, values = mapOf( @@ -41,7 +59,7 @@ val shortsActionButtonsPatch = resourcePatch( execute { // Check patch options first. - val iconType = iconType + val iconType = iconTypeOption .lowerCaseOrThrow() if (iconType == YOUTUBE_ICON) { @@ -50,40 +68,41 @@ val shortsActionButtonsPatch = resourcePatch( return@execute } - arrayOf( - "xxxhdpi", - "xxhdpi", - "xhdpi", - "hdpi", - "mdpi" - ).forEach { dpi -> - copyResources( - "youtube/shorts/actionbuttons/$iconType", - ResourceGroup( - "drawable-$dpi", - "ic_remix_filled_white_shadowed.webp", - "ic_right_comment_shadowed.webp", - "ic_right_dislike_off_shadowed.webp", - "ic_right_dislike_on_shadowed.webp", - "ic_right_like_off_shadowed.webp", - "ic_right_like_on_shadowed.webp", - "ic_right_share_shadowed.webp", - - // for older versions only - "ic_remix_filled_white_24.webp", - "ic_right_dislike_on_32c.webp", - "ic_right_like_on_32c.webp" - ), - ResourceGroup( - "drawable", - "ic_right_comment_32c.xml", - "ic_right_dislike_off_32c.xml", - "ic_right_like_off_32c.xml", - "ic_right_share_32c.xml" - ) - ) + val sourceResourceDirectory = "youtube/shorts/actionbuttons/$iconType" + + val resourceMap = ShortsActionButtons.entries.map { it.newResource to it.resources } + val res = get("res") + + for ((toFileName, fromResourceArray) in resourceMap) { + fromResourceArray.forEach { fromFileName -> + drawableDirectories.forEach { drawableDirectory -> + val fromFile = "$drawableDirectory/$fromFileName.webp" + val fromPath = res.resolve(fromFile).toPath() + val toFile = "$drawableDirectory/$toFileName.webp" + val toPath = res.resolve(toFile).toPath() + val inputStreamForLegacy = inputStreamFromBundledResourceOrThrow(sourceResourceDirectory, fromFile) + val inputStreamForNew = inputStreamFromBundledResourceOrThrow(sourceResourceDirectory, fromFile) + + Files.copy(inputStreamForLegacy, fromPath, StandardCopyOption.REPLACE_EXISTING) + + if (is_19_36_or_greater) { + Files.copy(inputStreamForNew, toPath, StandardCopyOption.REPLACE_EXISTING) + } + } + } } + copyResources( + sourceResourceDirectory, + ResourceGroup( + "drawable", + "ic_right_comment_32c.xml", + "ic_right_dislike_off_32c.xml", + "ic_right_like_off_32c.xml", + "ic_right_share_32c.xml" + ) + ) + addPreference(CUSTOM_SHORTS_ACTION_BUTTONS) if (iconType == DEFAULT_ICON) { @@ -99,6 +118,46 @@ val shortsActionButtonsPatch = resourcePatch( "reel_search_bold_24dp.xml" ) ) - } } + +internal enum class ShortsActionButtons(val newResource: String, vararg val resources: String) { + LIKE( + "youtube_shorts_like_outline_32dp", + // This replaces the new icon. + "ic_right_like_off_shadowed", + ), + LIKE_FILLED( + "youtube_shorts_like_fill_32dp", + "ic_right_like_on_32c", + // This replaces the new icon. + "ic_right_like_on_shadowed", + ), + DISLIKE( + "youtube_shorts_dislike_outline_32dp", + // This replaces the new icon. + "ic_right_dislike_off_shadowed", + ), + DISLIKE_FILLED( + "youtube_shorts_dislike_fill_32dp", + "ic_right_dislike_on_32c", + // This replaces the new icon. + "ic_right_dislike_on_shadowed", + ), + COMMENT( + "youtube_shorts_comment_outline_32dp", + // This replaces the new icon. + "ic_right_comment_shadowed", + ), + SHARE( + "youtube_shorts_share_outline_32dp", + // This replaces the new icon. + "ic_right_share_shadowed", + ), + REMIX( + "youtube_shorts_remix_outline_32dp", + "ic_remix_filled_white_24", + // This replaces the new icon. + "ic_remix_filled_white_shadowed", + ), +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt index 6f99c8fda..67f11cd14 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/AmbientModeSwitchPatch.kt @@ -6,15 +6,20 @@ import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.patch.PatchList.AMBIENT_MODE_CONTROL +import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater +import app.revanced.patches.youtube.utils.playservice.is_19_41_or_greater +import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.util.findMethodOrThrow import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.methodOrThrow +import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstStringInstructionOrThrow 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.reference.MethodReference @@ -26,7 +31,10 @@ val ambientModeSwitchPatch = bytecodePatch( ) { compatibleWith(COMPATIBLE_PACKAGE) - dependsOn(settingsPatch) + dependsOn( + settingsPatch, + versionCheckPatch, + ) execute { // region patch for bypass ambient mode restrictions @@ -83,10 +91,29 @@ val ambientModeSwitchPatch = bytecodePatch( // region patch for disable ambient mode in fullscreen - ambientModeInFullscreenFingerprint.injectLiteralInstructionBooleanCall( - 45389368L, - "$PLAYER_CLASS_DESCRIPTOR->disableAmbientModeInFullscreen()Z" - ) + if (!is_19_41_or_greater) { + ambientModeInFullscreenFingerprint.injectLiteralInstructionBooleanCall( + AMBIENT_MODE_IN_FULLSCREEN_FEATURE_FLAG, + "$PLAYER_CLASS_DESCRIPTOR->disableAmbientModeInFullscreen()Z" + ) + } + + if (is_19_34_or_greater) { + setFullScreenBackgroundColorFingerprint.methodOrThrow().apply { + val insertIndex = indexOfFirstInstructionReversedOrThrow { + getReference()?.name == "setBackgroundColor" + } + val register = getInstruction(insertIndex).registerD + + addInstructions( + insertIndex, + """ + invoke-static { v$register }, $PLAYER_CLASS_DESCRIPTOR->getFullScreenBackgroundColor(I)I + move-result v$register + """, + ) + } + } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/Fingerprints.kt index 901532aee..2ca53ebf6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/ambientmode/Fingerprints.kt @@ -4,10 +4,12 @@ import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags +internal const val AMBIENT_MODE_IN_FULLSCREEN_FEATURE_FLAG = 45389368L + internal val ambientModeInFullscreenFingerprint = legacyFingerprint( name = "ambientModeInFullscreenFingerprint", returnType = "V", - literals = listOf(45389368L), + literals = listOf(AMBIENT_MODE_IN_FULLSCREEN_FEATURE_FLAG), ) internal val powerSaveModeBroadcastReceiverFingerprint = legacyFingerprint( @@ -30,4 +32,15 @@ internal val powerSaveModeSyntheticFingerprint = legacyFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("Ljava/lang/Object;"), strings = listOf("android.os.action.POWER_SAVE_MODE_CHANGED") +) + +internal val setFullScreenBackgroundColorFingerprint = legacyFingerprint( + name = "setFullScreenBackgroundColorFingerprint", + returnType = "V", + accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("Z", "I", "I", "I", "I"), + customFingerprint = { method, classDef -> + classDef.type.endsWith("/YouTubePlayerViewNotForReflection;") + && method.name == "onLayout" + }, ) \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/buttons/PlayerButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/buttons/PlayerButtonsPatch.kt index 34b42a899..2cc40618e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/buttons/PlayerButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/buttons/PlayerButtonsPatch.kt @@ -14,22 +14,27 @@ import app.revanced.patches.youtube.utils.fix.bottomui.cfBottomUIPatch import app.revanced.patches.youtube.utils.layoutConstructorFingerprint import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_PLAYER_BUTTONS import app.revanced.patches.youtube.utils.playservice.is_18_31_or_greater +import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.resourceid.autoNavToggle import app.revanced.patches.youtube.utils.resourceid.fullScreenButton import app.revanced.patches.youtube.utils.resourceid.playerCollapseButton +import app.revanced.patches.youtube.utils.resourceid.playerControlPreviousButtonTouchArea import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.titleAnchor import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch 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.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.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.RegisterRangeInstruction import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference private const val HAS_NEXT = 5 private const val HAS_PREVIOUS = 6 @@ -162,21 +167,40 @@ val playerButtonsPatch = bytecodePatch( // region patch for hide previous and next button - playerControlsVisibilityModelFingerprint.methodOrThrow().apply { - val callIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT_RANGE) - val callInstruction = getInstruction(callIndex) + if (is_19_34_or_greater) { + layoutConstructorFingerprint.methodOrThrow().apply { + val resourceIndex = indexOfFirstLiteralInstructionOrThrow(playerControlPreviousButtonTouchArea) - val hasNextParameterRegister = callInstruction.startRegister + HAS_NEXT - val hasPreviousParameterRegister = callInstruction.startRegister + HAS_PREVIOUS + val insertIndex = indexOfFirstInstructionOrThrow(resourceIndex) { + opcode == Opcode.INVOKE_STATIC && + getReference()?.parameterTypes?.firstOrNull() == "Landroid/view/View;" + } - addInstructions( - callIndex, """ - invoke-static { v$hasNextParameterRegister }, $PLAYER_CLASS_DESCRIPTOR->hidePreviousNextButton(Z)Z - move-result v$hasNextParameterRegister - invoke-static { v$hasPreviousParameterRegister }, $PLAYER_CLASS_DESCRIPTOR->hidePreviousNextButton(Z)Z - move-result v$hasPreviousParameterRegister - """ - ) + val viewRegister = getInstruction(insertIndex).registerC + + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $PLAYER_CLASS_DESCRIPTOR" + + "->hidePreviousNextButtons(Landroid/view/View;)V", + ) + } + } else { + playerControlsVisibilityModelFingerprint.methodOrThrow().apply { + val callIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT_RANGE) + val callInstruction = getInstruction(callIndex) + + val hasNextParameterRegister = callInstruction.startRegister + HAS_NEXT + val hasPreviousParameterRegister = callInstruction.startRegister + HAS_PREVIOUS + + addInstructions( + callIndex, """ + invoke-static { v$hasNextParameterRegister }, $PLAYER_CLASS_DESCRIPTOR->hidePreviousNextButton(Z)Z + move-result v$hasNextParameterRegister + invoke-static { v$hasPreviousParameterRegister }, $PLAYER_CLASS_DESCRIPTOR->hidePreviousNextButton(Z)Z + move-result v$hasPreviousParameterRegister + """ + ) + } } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt index d0a493b91..33098e261 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt @@ -9,7 +9,6 @@ import app.revanced.patches.youtube.utils.resourceid.easySeekEduContainer import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutCircle import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutVideo -import app.revanced.patches.youtube.utils.resourceid.notice import app.revanced.patches.youtube.utils.resourceid.offlineActionsVideoDeletedUndoSnackbarText import app.revanced.patches.youtube.utils.resourceid.scrubbing import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing @@ -207,11 +206,12 @@ internal val lithoComponentOnClickListenerFingerprint = legacyFingerprint( literals = listOf(componentLongClickListener), ) -internal val noticeOnClickListenerFingerprint = legacyFingerprint( - name = "noticeOnClickListenerFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - literals = listOf(notice), +internal val engagementPanelPlaylistSyntheticFingerprint = legacyFingerprint( + name = "engagementPanelPlaylistSyntheticFingerprint", + strings = listOf("engagement-panel-playlist"), + customFingerprint = { _, classDef -> + classDef.interfaces.contains("Landroid/view/View${'$'}OnClickListener;") + } ) internal val offlineActionsOnClickListenerFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt index 5c80e027c..cfa71953e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt @@ -369,30 +369,32 @@ val playerComponentsPatch = bytecodePatch( arrayOf( lithoComponentOnClickListenerFingerprint, - noticeOnClickListenerFingerprint, offlineActionsOnClickListenerFingerprint, - startVideoInformerFingerprint, ).forEach { fingerprint -> fingerprint.methodOrThrow().apply { - if (fingerprint == startVideoInformerFingerprint) { - hookInitVideoPanel(1) + val syntheticIndex = + indexOfFirstInstruction(Opcode.NEW_INSTANCE) + if (syntheticIndex >= 0) { + val syntheticReference = + getInstruction(syntheticIndex).reference.toString() + + findMethodOrThrow(syntheticReference) { + name == "onClick" + }.hookInitVideoPanel(0) } else { - val syntheticIndex = - indexOfFirstInstruction(Opcode.NEW_INSTANCE) - if (syntheticIndex >= 0) { - val syntheticReference = - getInstruction(syntheticIndex).reference.toString() - - findMethodOrThrow(syntheticReference) { - name == "onClick" - }.hookInitVideoPanel(0) - } else { - println("WARNING: target Opcode not found in ${fingerprint.first}") - } + println("WARNING: target Opcode not found in ${fingerprint.first}") } } } + findMethodOrThrow( + engagementPanelPlaylistSyntheticFingerprint.methodOrThrow().definingClass + ) { + name == "onClick" + }.hookInitVideoPanel(0) + + startVideoInformerFingerprint.methodOrThrow().hookInitVideoPanel(1) + engagementPanelBuilderFingerprint.methodOrThrow().apply { addInstructionsWithLabels( 0, """ diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt index e236bd4f8..e391590f9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt @@ -16,8 +16,8 @@ import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch import app.revanced.patches.youtube.utils.playservice.is_18_49_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_02_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch -import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewHook -import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewPatch +import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch +import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.rollingNumberTextViewAnimationUpdateFingerprint import app.revanced.patches.youtube.utils.rollingNumberTextViewFingerprint @@ -43,9 +43,9 @@ val descriptionComponentsPatch = bytecodePatch( dependsOn( settingsPatch, - bottomSheetRecyclerViewPatch, lithoFilterPatch, playerTypeHookPatch, + recyclerViewTreeObserverPatch, sharedResourceIdPatch, versionCheckPatch, ) @@ -117,7 +117,7 @@ val descriptionComponentsPatch = bytecodePatch( ) } - bottomSheetRecyclerViewHook("$PLAYER_CLASS_DESCRIPTOR->onVideoDescriptionCreate(Landroid/support/v7/widget/RecyclerView;)V") + recyclerViewTreeObserverHook("$PLAYER_CLASS_DESCRIPTOR->onVideoDescriptionCreate(Landroid/support/v7/widget/RecyclerView;)V") settingArray += "SETTINGS: DESCRIPTION_INTERACTION" } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt index a904749c3..6c47216a9 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/fullscreen/FullscreenComponentsPatch.kt @@ -19,6 +19,7 @@ import app.revanced.patches.youtube.utils.layoutConstructorFingerprint import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch import app.revanced.patches.youtube.utils.patch.PatchList.FULLSCREEN_COMPONENTS import app.revanced.patches.youtube.utils.playservice.is_18_42_or_greater +import app.revanced.patches.youtube.utils.playservice.is_19_41_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.resourceid.autoNavPreviewStub import app.revanced.patches.youtube.utils.resourceid.fullScreenEngagementPanel @@ -293,7 +294,7 @@ val fullscreenComponentsPatch = bytecodePatch( // region patch for keep landscape mode - if (is_18_42_or_greater) { + if (is_18_42_or_greater && !is_19_41_or_greater) { landScapeModeConfigFingerprint.methodOrThrow().apply { val insertIndex = implementation!!.instructions.lastIndex val insertRegister = @@ -319,6 +320,8 @@ val fullscreenComponentsPatch = bytecodePatch( } settingArray += "SETTINGS: KEEP_LANDSCAPE_MODE" + } else { + println("WARNING: \"Keep landscape mode\" is not supported in this version. Use YouTube 19.16.39 or earlier.") } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt index 975c1430f..9c20c69a1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/overlaybuttons/OverlayButtonsPatch.kt @@ -201,64 +201,59 @@ val overlayButtonsPatch = resourcePatch( "android.support.constraint.ConstraintLayout" ) - // Modify the layout of fullscreen button for newer YouTube versions (19.09.xx+) - arrayOf( - "youtube_controls_bottom_ui_container.xml", - "youtube_controls_fullscreen_button.xml", - "youtube_controls_cf_fullscreen_button.xml", - ).forEach { xmlFile -> - val targetXml = get("res").resolve("layout").resolve(xmlFile) - if (targetXml.exists()) { - document("res/layout/$xmlFile").use { document -> - document.doRecursively loop@{ node -> - if (node !is Element) return@loop - - // Change the relationship between buttons - node.getAttributeNode("yt:layout_constraintRight_toLeftOf") - ?.let { attribute -> - if (attribute.textContent == "@id/fullscreen_button") { - attribute.textContent = "@+id/speed_dialog_button" - } - } - - val (id, height, width) = Triple( - node.getAttribute("android:id"), - node.getAttribute("android:layout_height"), - node.getAttribute("android:layout_width") - ) - val (heightIsNotZero, widthIsNotZero, isButton) = Triple( - height != "0.0dip", - width != "0.0dip", - id.endsWith("_button") || id == "@id/youtube_controls_fullscreen_button_stub" - ) - - // Adjust TimeBar and Chapter bottom padding - val timBarItem = mutableMapOf( - "@id/time_bar_chapter_title" to "16.0dip", - "@id/timestamps_container" to "14.0dip" - ) - - val layoutHeightWidth = if (widerButtonsSpace == true) - "56.0dip" - else - "48.0dip" - - if (isButton) { - node.setAttribute("android:layout_marginBottom", marginBottom) - node.setAttribute("android:paddingLeft", "0.0dip") - node.setAttribute("android:paddingRight", "0.0dip") - node.setAttribute("android:paddingBottom", "22.0dip") - if (heightIsNotZero && widthIsNotZero) { - node.setAttribute("android:layout_height", layoutHeightWidth) - node.setAttribute("android:layout_width", layoutHeightWidth) - } - } else if (timBarItem.containsKey(id)) { - node.setAttribute("android:layout_marginBottom", marginBottom) - if (widerButtonsSpace != true) { - node.setAttribute("android:paddingBottom", timBarItem.getValue(id)) - } + // Note: Do not modify fullscreen button and multiview button + document("res/layout/youtube_controls_bottom_ui_container.xml").use { document -> + document.doRecursively loop@{ node -> + if (node !is Element) return@loop + + // Change the relationship between buttons + node.getAttributeNode("yt:layout_constraintRight_toLeftOf") + ?.let { attribute -> + if (attribute.textContent == "@id/fullscreen_button") { + attribute.textContent = "@+id/speed_dialog_button" } } + + val (id, height, width) = Triple( + node.getAttribute("android:id"), + node.getAttribute("android:layout_height"), + node.getAttribute("android:layout_width") + ) + val (heightIsNotZero, widthIsNotZero, isButton) = Triple( + height != "0.0dip", + width != "0.0dip", + id.endsWith("_button") && id != "@id/multiview_button" + ) + + // Adjust TimeBar and Chapter bottom padding + val timBarItem = mutableMapOf( + "@id/time_bar_chapter_title" to "16.0dip", + "@id/timestamps_container" to "14.0dip" + ) + + val layoutHeightWidth = if (widerButtonsSpace == true) + "56.0dip" + else + "48.0dip" + + if (isButton) { + node.setAttribute("android:layout_marginBottom", marginBottom) + node.setAttribute("android:paddingLeft", "0.0dip") + node.setAttribute("android:paddingRight", "0.0dip") + node.setAttribute("android:paddingBottom", "22.0dip") + if (heightIsNotZero && widthIsNotZero) { + node.setAttribute("android:layout_height", layoutHeightWidth) + node.setAttribute("android:layout_width", layoutHeightWidth) + } + } else if (timBarItem.containsKey(id)) { + node.setAttribute("android:layout_marginBottom", marginBottom) + if (widerButtonsSpace != true) { + node.setAttribute("android:paddingBottom", timBarItem.getValue(id)) + } + } + + if (id.equals("@id/youtube_controls_fullscreen_button_stub")) { + node.setAttribute("android:layout_width", layoutHeightWidth) } } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt index 8d9bbc34c..18953b2ea 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/shorts/components/ShortsComponentPatch.kt @@ -37,8 +37,8 @@ import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_28_or_greater import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater import app.revanced.patches.youtube.utils.playservice.versionCheckPatch -import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewHook -import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewPatch +import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch +import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook import app.revanced.patches.youtube.utils.resourceid.bottomBarContainer import app.revanced.patches.youtube.utils.resourceid.metaPanel import app.revanced.patches.youtube.utils.resourceid.reelDynRemix @@ -158,9 +158,9 @@ private val shortsCustomActionsPatch = bytecodePatch( description = "shortsCustomActionsPatch" ) { dependsOn( - bottomSheetRecyclerViewPatch, lithoFilterPatch, playerTypeHookPatch, + recyclerViewTreeObserverPatch, toolBarHookPatch, videoIdPatch, videoInformationPatch, @@ -332,7 +332,7 @@ private val shortsCustomActionsPatch = bytecodePatch( } } - bottomSheetRecyclerViewHook("$EXTENSION_CUSTOM_ACTIONS_CLASS_DESCRIPTOR->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V") + recyclerViewTreeObserverHook("$EXTENSION_CUSTOM_ACTIONS_CLASS_DESCRIPTOR->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V") // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt index c57531270..98f0cef66 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt @@ -1,11 +1,15 @@ package app.revanced.patches.youtube.utils import app.revanced.patches.youtube.player.components.playerComponentsPatch +import app.revanced.patches.youtube.utils.resourceid.autoNavPreviewStub +import app.revanced.patches.youtube.utils.resourceid.autoNavToggle import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarColorizedBarPlayedColorDark import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarPlayedNotHighlightedColor import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout import app.revanced.patches.youtube.utils.resourceid.menuItemView +import app.revanced.patches.youtube.utils.resourceid.playerControlNextButtonTouchArea +import app.revanced.patches.youtube.utils.resourceid.playerControlPreviousButtonTouchArea import app.revanced.patches.youtube.utils.resourceid.scrimOverlay import app.revanced.patches.youtube.utils.resourceid.seekUndoEduOverlayStub import app.revanced.patches.youtube.utils.resourceid.totalTime @@ -62,7 +66,8 @@ internal val layoutConstructorFingerprint = legacyFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = emptyList(), - strings = listOf("1.0x") + strings = listOf("1.0x"), + literals = listOf(autoNavToggle, autoNavPreviewStub, playerControlPreviousButtonTouchArea, playerControlNextButtonTouchArea), ) internal val playbackRateBottomSheetBuilderFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt index d59ecb8e7..0ac2b447c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/compatibility/Constants.kt @@ -15,7 +15,7 @@ internal object Constants { "18.48.39", // This is the last version that do not use Rolling Number. "19.05.36", // This is the last version with the least YouTube experimental flag. "19.16.39", // This is the last version where the 'Restore old seekbar thumbnails' setting works. - "19.38.41", // This is the latest version supported by the RVX patch. + "19.44.39", // This is the latest version supported by the RVX patch. ) ) } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt index 73f157247..11ef1f932 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/cairo/Fingerprints.kt @@ -10,9 +10,11 @@ import com.android.tools.smali.dexlib2.AccessFlags * When this value is TRUE, Cairo Fragment is used. * In this case, some of patches may be broken, so set this value to FALSE. */ +internal const val CAIRO_FRAGMENT_FEATURE_FLAG = 45532100L + internal val carioFragmentConfigFingerprint = legacyFingerprint( name = "carioFragmentConfigFingerprint", returnType = "Z", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - literals = listOf(45532100L), + literals = listOf(CAIRO_FRAGMENT_FEATURE_FLAG), ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/Fingerprints.kt index def021552..5b6bb8741 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/Fingerprints.kt @@ -4,14 +4,21 @@ import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags -internal val bottomSheetRecyclerViewBuilderFingerprint = legacyFingerprint( - name = "bottomSheetRecyclerViewBuilderFingerprint", - literals = listOf(45382015L), +internal const val RECYCLER_VIEW_BUILDER_FEATURE_FLAG = 45382015L + +internal val recyclerViewBuilderFingerprint = legacyFingerprint( + name = "recyclerViewBuilderFingerprint", + literals = listOf(RECYCLER_VIEW_BUILDER_FEATURE_FLAG), ) internal val recyclerViewTreeObserverFingerprint = legacyFingerprint( name = "recyclerViewTreeObserverFingerprint", returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - strings = listOf("LithoRVSLCBinder") + strings = listOf("LithoRVSLCBinder"), + customFingerprint = { method, _ -> + val parameterTypes = method.parameterTypes + parameterTypes.size > 2 && + parameterTypes[1] == "Landroid/support/v7/widget/RecyclerView;" + } ) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/BottomSheetRecyclerViewPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/RecyclerViewTreeObserverPatch.kt similarity index 69% rename from patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/BottomSheetRecyclerViewPatch.kt rename to patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/RecyclerViewTreeObserverPatch.kt index 1fa445e42..3626d5d5f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/BottomSheetRecyclerViewPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/recyclerview/RecyclerViewTreeObserverPatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.methodOrThrow -import app.revanced.util.fingerprint.resolvable import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow @@ -15,29 +14,27 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference private lateinit var recyclerViewTreeObserverMutableMethod: MutableMethod private var recyclerViewTreeObserverInsertIndex = 0 -val bottomSheetRecyclerViewPatch = bytecodePatch( - description = "bottomSheetRecyclerViewPatch" +val recyclerViewTreeObserverPatch = bytecodePatch( + description = "recyclerViewTreeObserverPatch" ) { execute { /** - * If this value is false, OldQualityLayoutPatch and OldSpeedLayoutPatch will not work. + * If this value is false, RecyclerViewTreeObserver is not initialized. * This value is usually true so this patch is not strictly necessary, * But in very rare cases this value may be false. * Therefore, we need to force this to be true. */ - if (bottomSheetRecyclerViewBuilderFingerprint.resolvable()) { - bottomSheetRecyclerViewBuilderFingerprint.injectLiteralInstructionBooleanCall( - 45382015L, - "0x1" - ) - } + recyclerViewBuilderFingerprint.injectLiteralInstructionBooleanCall( + RECYCLER_VIEW_BUILDER_FEATURE_FLAG, + "0x1" + ) recyclerViewTreeObserverFingerprint.methodOrThrow().apply { recyclerViewTreeObserverMutableMethod = this val onDrawListenerIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.IPUT_OBJECT - && getReference()?.type == "Landroid/view/ViewTreeObserver${'$'}OnDrawListener;" + opcode == Opcode.IPUT_OBJECT && + getReference()?.type == "Landroid/view/ViewTreeObserver${'$'}OnDrawListener;" } recyclerViewTreeObserverInsertIndex = indexOfFirstInstructionReversedOrThrow(onDrawListenerIndex, Opcode.CHECK_CAST) + 1 @@ -45,7 +42,7 @@ val bottomSheetRecyclerViewPatch = bytecodePatch( } } -fun bottomSheetRecyclerViewHook(descriptor: String) = +fun recyclerViewTreeObserverHook(descriptor: String) = recyclerViewTreeObserverMutableMethod.addInstruction( recyclerViewTreeObserverInsertIndex++, "invoke-static/range { p2 .. p2 }, $descriptor" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt index 959faaedb..ddbf22d3d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt @@ -134,14 +134,16 @@ var modernMiniPlayerRewindButton = -1L private set var musicAppDeeplinkButtonView = -1L private set -var notice = -1L - private set var notificationBigPictureIconWidth = -1L private set var offlineActionsVideoDeletedUndoSnackbarText = -1L private set var playerCollapseButton = -1L private set +var playerControlPreviousButtonTouchArea = -1L + private set +var playerControlNextButtonTouchArea = -1L + private set var playerVideoTitleView = -1L private set var posterArtWidthDefault = -1L @@ -478,10 +480,6 @@ internal val sharedResourceIdPatch = resourcePatch( ID, "music_app_deeplink_button_view" ] - notice = resourceMappings[ - ID, - "notice" - ] notificationBigPictureIconWidth = resourceMappings[ DIMEN, "notification_big_picture_icon_width" @@ -494,6 +492,14 @@ internal val sharedResourceIdPatch = resourcePatch( ID, "player_collapse_button" ] + playerControlPreviousButtonTouchArea = resourceMappings[ + ID, + "player_control_previous_button_touch_area" + ] + playerControlNextButtonTouchArea = resourceMappings[ + ID, + "player_control_next_button_touch_area" + ] playerVideoTitleView = resourceMappings[ ID, "player_video_title_view" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt index e451ad762..2b770a3fb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/VideoPlaybackPatch.kt @@ -19,8 +19,8 @@ import app.revanced.patches.youtube.utils.flyoutmenu.flyoutMenuHookPatch import app.revanced.patches.youtube.utils.patch.PatchList.VIDEO_PLAYBACK import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch import app.revanced.patches.youtube.utils.qualityMenuViewInflateFingerprint -import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewHook -import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewPatch +import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch +import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.settingsPatch @@ -80,7 +80,6 @@ val videoPlaybackPatch = bytecodePatch( dependsOn( settingsPatch, - bottomSheetRecyclerViewPatch, customPlaybackSpeedPatch( "$VIDEO_PATH/CustomPlaybackSpeedPatch;", 8.0f @@ -88,6 +87,7 @@ val videoPlaybackPatch = bytecodePatch( flyoutMenuHookPatch, lithoFilterPatch, playerTypeHookPatch, + recyclerViewTreeObserverPatch, shortsPlaybackPatch, videoIdPatch, videoInformationPatch, @@ -102,7 +102,7 @@ val videoPlaybackPatch = bytecodePatch( // region patch for custom playback speed - bottomSheetRecyclerViewHook("$EXTENSION_CUSTOM_PLAYBACK_SPEED_CLASS_DESCRIPTOR->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V") + recyclerViewTreeObserverHook("$EXTENSION_CUSTOM_PLAYBACK_SPEED_CLASS_DESCRIPTOR->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V") addLithoFilter(PLAYBACK_SPEED_MENU_FILTER_CLASS_DESCRIPTOR) // endregion @@ -249,7 +249,7 @@ val videoPlaybackPatch = bytecodePatch( } ?: throw PatchException("Failed to find onItemClick method") } - bottomSheetRecyclerViewHook("$EXTENSION_RESTORE_OLD_VIDEO_QUALITY_MENU_CLASS_DESCRIPTOR->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V") + recyclerViewTreeObserverHook("$EXTENSION_RESTORE_OLD_VIDEO_QUALITY_MENU_CLASS_DESCRIPTOR->onFlyoutMenuCreate(Landroid/support/v7/widget/RecyclerView;)V") addLithoFilter(VIDEO_QUALITY_MENU_FILTER_CLASS_DESCRIPTOR) // endregion