feat(YouTube): Support version 19.44.39

This commit is contained in:
inotia00 2024-12-21 14:54:08 +09:00
parent 2b77e46f5e
commit dc0a5973ad
24 changed files with 294 additions and 181 deletions

View File

@ -18,6 +18,7 @@ public class SponsorBlockSettings {
public void settingsImported(@Nullable Context context) { public void settingsImported(@Nullable Context context) {
SegmentCategory.loadAllCategoriesFromSettings(); SegmentCategory.loadAllCategoriesFromSettings();
} }
@Override @Override
public void settingsExported(@Nullable Context context) { public void settingsExported(@Nullable Context context) {
} }

View File

@ -2,7 +2,6 @@ package app.revanced.extension.music.utils;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.util.TypedValue;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;

View File

@ -64,14 +64,14 @@ public class GmsCoreSupport {
// Use a delay to allow the activity to finish initializing. // Use a delay to allow the activity to finish initializing.
// Otherwise, if device is in dark mode the dialog is shown with wrong color scheme. // Otherwise, if device is in dark mode the dialog is shown with wrong color scheme.
Utils.runOnMainThreadDelayed(() -> Utils.runOnMainThreadDelayed(() ->
// Do not set cancelable to false, to allow using back button to skip the action, // Do not set cancelable to false, to allow using back button to skip the action,
// just in case the battery change can never be satisfied. // just in case the battery change can never be satisfied.
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setIconAttribute(android.R.attr.alertDialogIcon) .setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle(str("gms_core_dialog_title")) .setTitle(str("gms_core_dialog_title"))
.setMessage(str(dialogMessageRef)) .setMessage(str(dialogMessageRef))
.setPositiveButton(str(positiveButtonTextRef), onPositiveClickListener) .setPositiveButton(str(positiveButtonTextRef), onPositiveClickListener)
.show(), .show(),
100 100
); );
} }

View File

@ -74,6 +74,11 @@ public class PlayerPatch {
// region [Ambient mode control] patch // 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) { public static boolean bypassAmbientModeRestrictions(boolean original) {
return (!Settings.BYPASS_AMBIENT_MODE_RESTRICTIONS.get() && original) || Settings.DISABLE_AMBIENT_MODE.get(); return (!Settings.BYPASS_AMBIENT_MODE_RESTRICTIONS.get() && original) || Settings.DISABLE_AMBIENT_MODE.get();
} }
@ -82,6 +87,14 @@ public class PlayerPatch {
return !Settings.DISABLE_AMBIENT_MODE_IN_FULLSCREEN.get(); 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 // endregion
// region [Change player flyout menu toggles] patch // region [Change player flyout menu toggles] patch
@ -424,6 +437,35 @@ public class PlayerPatch {
return !Settings.HIDE_PLAYER_PREVIOUS_NEXT_BUTTON.get() && 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() { public static boolean hideMusicButton() {
return Settings.HIDE_PLAYER_YOUTUBE_MUSIC_BUTTON.get(); return Settings.HIDE_PLAYER_YOUTUBE_MUSIC_BUTTON.get();
} }

View File

@ -1,5 +1,10 @@
package app.revanced.extension.youtube.patches.shorts; 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.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
@ -10,13 +15,26 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.StateListDrawable;
import android.support.v7.widget.RecyclerView; 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.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; 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.settings.BooleanSetting;
import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.Logger;
import app.revanced.extension.shared.utils.ResourceUtils; import app.revanced.extension.shared.utils.ResourceUtils;
@ -26,17 +44,6 @@ import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.ShortsPlayerState; import app.revanced.extension.youtube.shared.ShortsPlayerState;
import app.revanced.extension.youtube.utils.ThemeUtils; import app.revanced.extension.youtube.utils.ThemeUtils;
import app.revanced.extension.youtube.utils.VideoUtils; 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") @SuppressWarnings("unused")
public final class CustomActionsPatch { public final class CustomActionsPatch {

View File

@ -34,6 +34,7 @@ public class SponsorBlockSettings {
SegmentCategory.loadAllCategoriesFromSettings(); SegmentCategory.loadAllCategoriesFromSettings();
SponsorBlockSettingsPreference.updateSegmentCategories(); SponsorBlockSettingsPreference.updateSegmentCategories();
} }
@Override @Override
public void settingsExported(@Nullable Context context) { public void settingsExported(@Nullable Context context) {
showExportWarningIfNeeded(context); showExportWarningIfNeeded(context);

View File

@ -22,11 +22,11 @@ internal val actionBarRingoBackgroundFingerprint = legacyFingerprint(
returnType = "Landroid/view/View;", returnType = "Landroid/view/View;",
literals = listOf(actionBarRingoBackground), literals = listOf(actionBarRingoBackground),
customFingerprint = { method, _ -> customFingerprint = { method, _ ->
indexOfStaticInstruction(method) >= 0 indexOfActionBarRingoBackgroundTabletInstruction(method) >= 0
} }
) )
internal fun indexOfStaticInstruction(method: Method) = internal fun indexOfActionBarRingoBackgroundTabletInstruction(method: Method) =
method.indexOfFirstInstruction { method.indexOfFirstInstruction {
val reference = getReference<MethodReference>() val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_STATIC && opcode == Opcode.INVOKE_STATIC &&
@ -54,7 +54,7 @@ internal val actionBarRingoTextFingerprint = legacyFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { method, _ -> customFingerprint = { method, _ ->
indexOfStartDelayInstruction(method) >= 0 && indexOfStartDelayInstruction(method) >= 0 &&
indexOfStaticInstructions(method) >= 0 indexOfActionBarRingoTextTabletInstructions(method) >= 0
} }
) )
@ -64,7 +64,7 @@ internal fun indexOfStartDelayInstruction(method: Method) =
getReference<MethodReference>()?.name == "setStartDelay" getReference<MethodReference>()?.name == "setStartDelay"
} }
internal fun indexOfStaticInstructions(method: Method) = internal fun indexOfActionBarRingoTextTabletInstructions(method: Method) =
method.indexOfFirstInstructionReversed(indexOfStartDelayInstruction(method)) { method.indexOfFirstInstructionReversed(indexOfStartDelayInstruction(method)) {
val reference = getReference<MethodReference>() val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_STATIC && opcode == Opcode.INVOKE_STATIC &&
@ -175,24 +175,6 @@ internal val setActionBarRingoFingerprint = legacyFingerprint(
literals = listOf(actionBarRingo), 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") @Suppress("SpellCheckingInspection")
internal val yoodlesImageViewFingerprint = legacyFingerprint( internal val yoodlesImageViewFingerprint = legacyFingerprint(
name = "yoodlesImageViewFingerprint", name = "yoodlesImageViewFingerprint",

View File

@ -169,7 +169,7 @@ val toolBarComponentsPatch = bytecodePatch(
"invoke-static {v$viewRegister}, $GENERAL_CLASS_DESCRIPTOR->setWideSearchBarLayout(Landroid/view/View;)V" "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<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
injectSearchBarHook( injectSearchBarHook(
@ -180,7 +180,7 @@ val toolBarComponentsPatch = bytecodePatch(
} }
actionBarRingoTextFingerprint.methodOrThrow(actionBarRingoBackgroundFingerprint).apply { actionBarRingoTextFingerprint.methodOrThrow(actionBarRingoBackgroundFingerprint).apply {
val targetIndex = indexOfStaticInstruction(this) + 1 val targetIndex = indexOfActionBarRingoTextTabletInstructions(this) + 1
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
injectSearchBarHook( injectSearchBarHook(

View File

@ -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.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR 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.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.ResourceUtils.addPreference
import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.patches.youtube.utils.settings.settingsPatch
import app.revanced.util.findMethodOrThrow import app.revanced.util.findMethodOrThrow
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.indexOfFirstStringInstructionOrThrow import app.revanced.util.indexOfFirstStringInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode 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.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -26,7 +31,10 @@ val ambientModeSwitchPatch = bytecodePatch(
) { ) {
compatibleWith(COMPATIBLE_PACKAGE) compatibleWith(COMPATIBLE_PACKAGE)
dependsOn(settingsPatch) dependsOn(
settingsPatch,
versionCheckPatch,
)
execute { execute {
// region patch for bypass ambient mode restrictions // region patch for bypass ambient mode restrictions
@ -83,10 +91,29 @@ val ambientModeSwitchPatch = bytecodePatch(
// region patch for disable ambient mode in fullscreen // region patch for disable ambient mode in fullscreen
ambientModeInFullscreenFingerprint.injectLiteralInstructionBooleanCall( if (!is_19_41_or_greater) {
45389368L, ambientModeInFullscreenFingerprint.injectLiteralInstructionBooleanCall(
"$PLAYER_CLASS_DESCRIPTOR->disableAmbientModeInFullscreen()Z" AMBIENT_MODE_IN_FULLSCREEN_FEATURE_FLAG,
) "$PLAYER_CLASS_DESCRIPTOR->disableAmbientModeInFullscreen()Z"
)
}
if (is_19_34_or_greater) {
setFullScreenBackgroundColorFingerprint.methodOrThrow().apply {
val insertIndex = indexOfFirstInstructionReversedOrThrow {
getReference<MethodReference>()?.name == "setBackgroundColor"
}
val register = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
addInstructions(
insertIndex,
"""
invoke-static { v$register }, $PLAYER_CLASS_DESCRIPTOR->getFullScreenBackgroundColor(I)I
move-result v$register
""",
)
}
}
// endregion // endregion

View File

@ -4,10 +4,12 @@ import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal const val AMBIENT_MODE_IN_FULLSCREEN_FEATURE_FLAG = 45389368L
internal val ambientModeInFullscreenFingerprint = legacyFingerprint( internal val ambientModeInFullscreenFingerprint = legacyFingerprint(
name = "ambientModeInFullscreenFingerprint", name = "ambientModeInFullscreenFingerprint",
returnType = "V", returnType = "V",
literals = listOf(45389368L), literals = listOf(AMBIENT_MODE_IN_FULLSCREEN_FEATURE_FLAG),
) )
internal val powerSaveModeBroadcastReceiverFingerprint = legacyFingerprint( internal val powerSaveModeBroadcastReceiverFingerprint = legacyFingerprint(
@ -30,4 +32,15 @@ internal val powerSaveModeSyntheticFingerprint = legacyFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Ljava/lang/Object;"), parameters = listOf("Ljava/lang/Object;"),
strings = listOf("android.os.action.POWER_SAVE_MODE_CHANGED") 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"
},
) )

View File

@ -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.layoutConstructorFingerprint
import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_PLAYER_BUTTONS 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_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.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.autoNavToggle import app.revanced.patches.youtube.utils.resourceid.autoNavToggle
import app.revanced.patches.youtube.utils.resourceid.fullScreenButton import app.revanced.patches.youtube.utils.resourceid.fullScreenButton
import app.revanced.patches.youtube.utils.resourceid.playerCollapseButton 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.sharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.titleAnchor import app.revanced.patches.youtube.utils.resourceid.titleAnchor
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.patches.youtube.utils.settings.settingsPatch
import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.matchOrThrow
import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode 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.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.RegisterRangeInstruction 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.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val HAS_NEXT = 5 private const val HAS_NEXT = 5
private const val HAS_PREVIOUS = 6 private const val HAS_PREVIOUS = 6
@ -162,21 +167,40 @@ val playerButtonsPatch = bytecodePatch(
// region patch for hide previous and next button // region patch for hide previous and next button
playerControlsVisibilityModelFingerprint.methodOrThrow().apply { if (is_19_34_or_greater) {
val callIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT_RANGE) layoutConstructorFingerprint.methodOrThrow().apply {
val callInstruction = getInstruction<RegisterRangeInstruction>(callIndex) val resourceIndex = indexOfFirstLiteralInstructionOrThrow(playerControlPreviousButtonTouchArea)
val hasNextParameterRegister = callInstruction.startRegister + HAS_NEXT val insertIndex = indexOfFirstInstructionOrThrow(resourceIndex) {
val hasPreviousParameterRegister = callInstruction.startRegister + HAS_PREVIOUS opcode == Opcode.INVOKE_STATIC &&
getReference<MethodReference>()?.parameterTypes?.firstOrNull() == "Landroid/view/View;"
}
addInstructions( val viewRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerC
callIndex, """
invoke-static { v$hasNextParameterRegister }, $PLAYER_CLASS_DESCRIPTOR->hidePreviousNextButton(Z)Z addInstruction(
move-result v$hasNextParameterRegister insertIndex,
invoke-static { v$hasPreviousParameterRegister }, $PLAYER_CLASS_DESCRIPTOR->hidePreviousNextButton(Z)Z "invoke-static { v$viewRegister }, $PLAYER_CLASS_DESCRIPTOR" +
move-result v$hasPreviousParameterRegister "->hidePreviousNextButtons(Landroid/view/View;)V",
""" )
) }
} else {
playerControlsVisibilityModelFingerprint.methodOrThrow().apply {
val callIndex = indexOfFirstInstructionOrThrow(Opcode.INVOKE_DIRECT_RANGE)
val callInstruction = getInstruction<RegisterRangeInstruction>(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 // endregion

View File

@ -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.endScreenElementLayoutCircle
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutVideo 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.offlineActionsVideoDeletedUndoSnackbarText
import app.revanced.patches.youtube.utils.resourceid.scrubbing import app.revanced.patches.youtube.utils.resourceid.scrubbing
import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing
@ -207,11 +206,12 @@ internal val lithoComponentOnClickListenerFingerprint = legacyFingerprint(
literals = listOf(componentLongClickListener), literals = listOf(componentLongClickListener),
) )
internal val noticeOnClickListenerFingerprint = legacyFingerprint( internal val engagementPanelPlaylistSyntheticFingerprint = legacyFingerprint(
name = "noticeOnClickListenerFingerprint", name = "engagementPanelPlaylistSyntheticFingerprint",
returnType = "V", strings = listOf("engagement-panel-playlist"),
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, customFingerprint = { _, classDef ->
literals = listOf(notice), classDef.interfaces.contains("Landroid/view/View${'$'}OnClickListener;")
}
) )
internal val offlineActionsOnClickListenerFingerprint = legacyFingerprint( internal val offlineActionsOnClickListenerFingerprint = legacyFingerprint(

View File

@ -369,30 +369,32 @@ val playerComponentsPatch = bytecodePatch(
arrayOf( arrayOf(
lithoComponentOnClickListenerFingerprint, lithoComponentOnClickListenerFingerprint,
noticeOnClickListenerFingerprint,
offlineActionsOnClickListenerFingerprint, offlineActionsOnClickListenerFingerprint,
startVideoInformerFingerprint,
).forEach { fingerprint -> ).forEach { fingerprint ->
fingerprint.methodOrThrow().apply { fingerprint.methodOrThrow().apply {
if (fingerprint == startVideoInformerFingerprint) { val syntheticIndex =
hookInitVideoPanel(1) indexOfFirstInstruction(Opcode.NEW_INSTANCE)
} else { if (syntheticIndex >= 0) {
val syntheticIndex = val syntheticReference =
indexOfFirstInstruction(Opcode.NEW_INSTANCE) getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
if (syntheticIndex >= 0) {
val syntheticReference =
getInstruction<ReferenceInstruction>(syntheticIndex).reference.toString()
findMethodOrThrow(syntheticReference) { findMethodOrThrow(syntheticReference) {
name == "onClick" name == "onClick"
}.hookInitVideoPanel(0) }.hookInitVideoPanel(0)
} else { } 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 { engagementPanelBuilderFingerprint.methodOrThrow().apply {
addInstructionsWithLabels( addInstructionsWithLabels(
0, """ 0, """

View File

@ -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_18_49_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_02_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.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewHook import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch
import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewPatch import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.patches.youtube.utils.rollingNumberTextViewAnimationUpdateFingerprint import app.revanced.patches.youtube.utils.rollingNumberTextViewAnimationUpdateFingerprint
import app.revanced.patches.youtube.utils.rollingNumberTextViewFingerprint import app.revanced.patches.youtube.utils.rollingNumberTextViewFingerprint
@ -43,9 +43,9 @@ val descriptionComponentsPatch = bytecodePatch(
dependsOn( dependsOn(
settingsPatch, settingsPatch,
bottomSheetRecyclerViewPatch,
lithoFilterPatch, lithoFilterPatch,
playerTypeHookPatch, playerTypeHookPatch,
recyclerViewTreeObserverPatch,
sharedResourceIdPatch, sharedResourceIdPatch,
versionCheckPatch, 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" settingArray += "SETTINGS: DESCRIPTION_INTERACTION"
} }

View File

@ -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.mainactivity.mainActivityResolvePatch
import app.revanced.patches.youtube.utils.patch.PatchList.FULLSCREEN_COMPONENTS 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_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.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.autoNavPreviewStub import app.revanced.patches.youtube.utils.resourceid.autoNavPreviewStub
import app.revanced.patches.youtube.utils.resourceid.fullScreenEngagementPanel import app.revanced.patches.youtube.utils.resourceid.fullScreenEngagementPanel
@ -293,7 +294,7 @@ val fullscreenComponentsPatch = bytecodePatch(
// region patch for keep landscape mode // 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 { landScapeModeConfigFingerprint.methodOrThrow().apply {
val insertIndex = implementation!!.instructions.lastIndex val insertIndex = implementation!!.instructions.lastIndex
val insertRegister = val insertRegister =
@ -319,6 +320,8 @@ val fullscreenComponentsPatch = bytecodePatch(
} }
settingArray += "SETTINGS: KEEP_LANDSCAPE_MODE" 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 // endregion

View File

@ -201,64 +201,59 @@ val overlayButtonsPatch = resourcePatch(
"android.support.constraint.ConstraintLayout" "android.support.constraint.ConstraintLayout"
) )
// Modify the layout of fullscreen button for newer YouTube versions (19.09.xx+) // Note: Do not modify fullscreen button and multiview button
arrayOf( document("res/layout/youtube_controls_bottom_ui_container.xml").use { document ->
"youtube_controls_bottom_ui_container.xml", document.doRecursively loop@{ node ->
"youtube_controls_fullscreen_button.xml", if (node !is Element) return@loop
"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 // Change the relationship between buttons
node.getAttributeNode("yt:layout_constraintRight_toLeftOf") node.getAttributeNode("yt:layout_constraintRight_toLeftOf")
?.let { attribute -> ?.let { attribute ->
if (attribute.textContent == "@id/fullscreen_button") { if (attribute.textContent == "@id/fullscreen_button") {
attribute.textContent = "@+id/speed_dialog_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))
}
} }
} }
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)
} }
} }
} }

View File

@ -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_28_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_34_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.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewHook import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch
import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewPatch import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook
import app.revanced.patches.youtube.utils.resourceid.bottomBarContainer import app.revanced.patches.youtube.utils.resourceid.bottomBarContainer
import app.revanced.patches.youtube.utils.resourceid.metaPanel import app.revanced.patches.youtube.utils.resourceid.metaPanel
import app.revanced.patches.youtube.utils.resourceid.reelDynRemix import app.revanced.patches.youtube.utils.resourceid.reelDynRemix
@ -158,9 +158,9 @@ private val shortsCustomActionsPatch = bytecodePatch(
description = "shortsCustomActionsPatch" description = "shortsCustomActionsPatch"
) { ) {
dependsOn( dependsOn(
bottomSheetRecyclerViewPatch,
lithoFilterPatch, lithoFilterPatch,
playerTypeHookPatch, playerTypeHookPatch,
recyclerViewTreeObserverPatch,
toolBarHookPatch, toolBarHookPatch,
videoIdPatch, videoIdPatch,
videoInformationPatch, 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 // endregion

View File

@ -1,11 +1,15 @@
package app.revanced.patches.youtube.utils package app.revanced.patches.youtube.utils
import app.revanced.patches.youtube.player.components.playerComponentsPatch 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.fadeDurationFast
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarColorizedBarPlayedColorDark import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarColorizedBarPlayedColorDark
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarPlayedNotHighlightedColor import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarPlayedNotHighlightedColor
import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout
import app.revanced.patches.youtube.utils.resourceid.menuItemView 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.scrimOverlay
import app.revanced.patches.youtube.utils.resourceid.seekUndoEduOverlayStub import app.revanced.patches.youtube.utils.resourceid.seekUndoEduOverlayStub
import app.revanced.patches.youtube.utils.resourceid.totalTime import app.revanced.patches.youtube.utils.resourceid.totalTime
@ -62,7 +66,8 @@ internal val layoutConstructorFingerprint = legacyFingerprint(
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(), parameters = emptyList(),
strings = listOf("1.0x") strings = listOf("1.0x"),
literals = listOf(autoNavToggle, autoNavPreviewStub, playerControlPreviousButtonTouchArea, playerControlNextButtonTouchArea),
) )
internal val playbackRateBottomSheetBuilderFingerprint = legacyFingerprint( internal val playbackRateBottomSheetBuilderFingerprint = legacyFingerprint(

View File

@ -15,7 +15,7 @@ internal object Constants {
"18.48.39", // This is the last version that do not use Rolling Number. "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.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.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.
) )
) )
} }

View File

@ -10,9 +10,11 @@ import com.android.tools.smali.dexlib2.AccessFlags
* When this value is TRUE, Cairo Fragment is used. * When this value is TRUE, Cairo Fragment is used.
* In this case, some of patches may be broken, so set this value to FALSE. * 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( internal val carioFragmentConfigFingerprint = legacyFingerprint(
name = "carioFragmentConfigFingerprint", name = "carioFragmentConfigFingerprint",
returnType = "Z", returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
literals = listOf(45532100L), literals = listOf(CAIRO_FRAGMENT_FEATURE_FLAG),
) )

View File

@ -4,14 +4,21 @@ import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.or import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
internal val bottomSheetRecyclerViewBuilderFingerprint = legacyFingerprint( internal const val RECYCLER_VIEW_BUILDER_FEATURE_FLAG = 45382015L
name = "bottomSheetRecyclerViewBuilderFingerprint",
literals = listOf(45382015L), internal val recyclerViewBuilderFingerprint = legacyFingerprint(
name = "recyclerViewBuilderFingerprint",
literals = listOf(RECYCLER_VIEW_BUILDER_FEATURE_FLAG),
) )
internal val recyclerViewTreeObserverFingerprint = legacyFingerprint( internal val recyclerViewTreeObserverFingerprint = legacyFingerprint(
name = "recyclerViewTreeObserverFingerprint", name = "recyclerViewTreeObserverFingerprint",
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, 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;"
}
) )

View File

@ -5,7 +5,6 @@ import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.fingerprint.resolvable
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
@ -15,29 +14,27 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private lateinit var recyclerViewTreeObserverMutableMethod: MutableMethod private lateinit var recyclerViewTreeObserverMutableMethod: MutableMethod
private var recyclerViewTreeObserverInsertIndex = 0 private var recyclerViewTreeObserverInsertIndex = 0
val bottomSheetRecyclerViewPatch = bytecodePatch( val recyclerViewTreeObserverPatch = bytecodePatch(
description = "bottomSheetRecyclerViewPatch" description = "recyclerViewTreeObserverPatch"
) { ) {
execute { 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, * This value is usually true so this patch is not strictly necessary,
* But in very rare cases this value may be false. * But in very rare cases this value may be false.
* Therefore, we need to force this to be true. * Therefore, we need to force this to be true.
*/ */
if (bottomSheetRecyclerViewBuilderFingerprint.resolvable()) { recyclerViewBuilderFingerprint.injectLiteralInstructionBooleanCall(
bottomSheetRecyclerViewBuilderFingerprint.injectLiteralInstructionBooleanCall( RECYCLER_VIEW_BUILDER_FEATURE_FLAG,
45382015L, "0x1"
"0x1" )
)
}
recyclerViewTreeObserverFingerprint.methodOrThrow().apply { recyclerViewTreeObserverFingerprint.methodOrThrow().apply {
recyclerViewTreeObserverMutableMethod = this recyclerViewTreeObserverMutableMethod = this
val onDrawListenerIndex = indexOfFirstInstructionOrThrow { val onDrawListenerIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT opcode == Opcode.IPUT_OBJECT &&
&& getReference<FieldReference>()?.type == "Landroid/view/ViewTreeObserver${'$'}OnDrawListener;" getReference<FieldReference>()?.type == "Landroid/view/ViewTreeObserver${'$'}OnDrawListener;"
} }
recyclerViewTreeObserverInsertIndex = recyclerViewTreeObserverInsertIndex =
indexOfFirstInstructionReversedOrThrow(onDrawListenerIndex, Opcode.CHECK_CAST) + 1 indexOfFirstInstructionReversedOrThrow(onDrawListenerIndex, Opcode.CHECK_CAST) + 1
@ -45,7 +42,7 @@ val bottomSheetRecyclerViewPatch = bytecodePatch(
} }
} }
fun bottomSheetRecyclerViewHook(descriptor: String) = fun recyclerViewTreeObserverHook(descriptor: String) =
recyclerViewTreeObserverMutableMethod.addInstruction( recyclerViewTreeObserverMutableMethod.addInstruction(
recyclerViewTreeObserverInsertIndex++, recyclerViewTreeObserverInsertIndex++,
"invoke-static/range { p2 .. p2 }, $descriptor" "invoke-static/range { p2 .. p2 }, $descriptor"

View File

@ -134,14 +134,16 @@ var modernMiniPlayerRewindButton = -1L
private set private set
var musicAppDeeplinkButtonView = -1L var musicAppDeeplinkButtonView = -1L
private set private set
var notice = -1L
private set
var notificationBigPictureIconWidth = -1L var notificationBigPictureIconWidth = -1L
private set private set
var offlineActionsVideoDeletedUndoSnackbarText = -1L var offlineActionsVideoDeletedUndoSnackbarText = -1L
private set private set
var playerCollapseButton = -1L var playerCollapseButton = -1L
private set private set
var playerControlPreviousButtonTouchArea = -1L
private set
var playerControlNextButtonTouchArea = -1L
private set
var playerVideoTitleView = -1L var playerVideoTitleView = -1L
private set private set
var posterArtWidthDefault = -1L var posterArtWidthDefault = -1L
@ -478,10 +480,6 @@ internal val sharedResourceIdPatch = resourcePatch(
ID, ID,
"music_app_deeplink_button_view" "music_app_deeplink_button_view"
] ]
notice = resourceMappings[
ID,
"notice"
]
notificationBigPictureIconWidth = resourceMappings[ notificationBigPictureIconWidth = resourceMappings[
DIMEN, DIMEN,
"notification_big_picture_icon_width" "notification_big_picture_icon_width"
@ -494,6 +492,14 @@ internal val sharedResourceIdPatch = resourcePatch(
ID, ID,
"player_collapse_button" "player_collapse_button"
] ]
playerControlPreviousButtonTouchArea = resourceMappings[
ID,
"player_control_previous_button_touch_area"
]
playerControlNextButtonTouchArea = resourceMappings[
ID,
"player_control_next_button_touch_area"
]
playerVideoTitleView = resourceMappings[ playerVideoTitleView = resourceMappings[
ID, ID,
"player_video_title_view" "player_video_title_view"

View File

@ -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.patch.PatchList.VIDEO_PLAYBACK
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.utils.qualityMenuViewInflateFingerprint import app.revanced.patches.youtube.utils.qualityMenuViewInflateFingerprint
import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewHook import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverPatch
import app.revanced.patches.youtube.utils.recyclerview.bottomSheetRecyclerViewPatch import app.revanced.patches.youtube.utils.recyclerview.recyclerViewTreeObserverHook
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.patches.youtube.utils.settings.settingsPatch
@ -80,7 +80,6 @@ val videoPlaybackPatch = bytecodePatch(
dependsOn( dependsOn(
settingsPatch, settingsPatch,
bottomSheetRecyclerViewPatch,
customPlaybackSpeedPatch( customPlaybackSpeedPatch(
"$VIDEO_PATH/CustomPlaybackSpeedPatch;", "$VIDEO_PATH/CustomPlaybackSpeedPatch;",
8.0f 8.0f
@ -88,6 +87,7 @@ val videoPlaybackPatch = bytecodePatch(
flyoutMenuHookPatch, flyoutMenuHookPatch,
lithoFilterPatch, lithoFilterPatch,
playerTypeHookPatch, playerTypeHookPatch,
recyclerViewTreeObserverPatch,
shortsPlaybackPatch, shortsPlaybackPatch,
videoIdPatch, videoIdPatch,
videoInformationPatch, videoInformationPatch,
@ -102,7 +102,7 @@ val videoPlaybackPatch = bytecodePatch(
// region patch for custom playback speed // 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) addLithoFilter(PLAYBACK_SPEED_MENU_FILTER_CLASS_DESCRIPTOR)
// endregion // endregion
@ -249,7 +249,7 @@ val videoPlaybackPatch = bytecodePatch(
} ?: throw PatchException("Failed to find onItemClick method") } ?: 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) addLithoFilter(VIDEO_QUALITY_MENU_FILTER_CLASS_DESCRIPTOR)
// endregion // endregion