feat(YouTube - Shorts components): Add Open Shorts in regular player setting

This commit is contained in:
inotia00
2025-01-18 20:25:19 +09:00
parent ba696a86df
commit 8e1bee1113
6 changed files with 126 additions and 1 deletions

View File

@ -16,9 +16,11 @@ import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import app.revanced.extension.shared.utils.Logger;
import app.revanced.extension.shared.utils.ResourceUtils; import app.revanced.extension.shared.utils.ResourceUtils;
import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.shared.utils.Utils;
import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
import app.revanced.extension.youtube.shared.ShortsPlayerState; import app.revanced.extension.youtube.shared.ShortsPlayerState;
import app.revanced.extension.youtube.utils.VideoUtils; import app.revanced.extension.youtube.utils.VideoUtils;
import kotlin.Unit; import kotlin.Unit;
@ -216,4 +218,38 @@ public class ShortsPatch {
return !Settings.RESTORE_SHORTS_OLD_PLAYER_LAYOUT.get(); return !Settings.RESTORE_SHORTS_OLD_PLAYER_LAYOUT.get();
} }
public static boolean openShortInRegularPlayer(String videoId) {
try {
if (!Settings.OPEN_SHORTS_IN_REGULAR_PLAYER.get()) {
return false; // Default unpatched behavior.
}
if (videoId.isEmpty()) {
// Shorts was opened using launcher app shortcut.
//
// This check will not detect if the Shorts app shortcut is used
// while the app is running in the background (instead the regular player is opened).
// To detect that the hooked method map parameter can be checked
// if integer key 'com.google.android.apps.youtube.app.endpoint.flags'
// has bitmask 16 set.
//
// This use case seems unlikely if the user has the Shorts
// set to open in the regular player, so it's ignored as
// checking the map makes the patch more complicated.
Logger.printDebug(() -> "Ignoring Short with no videoId");
return false;
}
if (NavigationButton.getSelectedNavigationButton() == NavigationButton.SHORTS) {
return false; // Always use Shorts player for the Shorts nav button.
}
VideoUtils.openVideo(videoId, true);
return true;
} catch (Exception ex) {
Logger.printException(() -> "openShortInRegularPlayer failure", ex);
return false;
}
}
} }

View File

@ -433,6 +433,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_SHORTS_SHELF_HISTORY = new BooleanSetting("revanced_hide_shorts_shelf_history", TRUE); public static final BooleanSetting HIDE_SHORTS_SHELF_HISTORY = new BooleanSetting("revanced_hide_shorts_shelf_history", TRUE);
public static final EnumSetting<ShortsLoopBehavior> CHANGE_SHORTS_BACKGROUND_REPEAT_STATE = new EnumSetting<>("revanced_change_shorts_background_repeat_state", ShortsLoopBehavior.UNKNOWN); public static final EnumSetting<ShortsLoopBehavior> CHANGE_SHORTS_BACKGROUND_REPEAT_STATE = new EnumSetting<>("revanced_change_shorts_background_repeat_state", ShortsLoopBehavior.UNKNOWN);
public static final EnumSetting<ShortsLoopBehavior> CHANGE_SHORTS_REPEAT_STATE = new EnumSetting<>("revanced_change_shorts_repeat_state", ShortsLoopBehavior.UNKNOWN); public static final EnumSetting<ShortsLoopBehavior> CHANGE_SHORTS_REPEAT_STATE = new EnumSetting<>("revanced_change_shorts_repeat_state", ShortsLoopBehavior.UNKNOWN);
public static final BooleanSetting OPEN_SHORTS_IN_REGULAR_PLAYER = new BooleanSetting("revanced_open_shorts_in_regular_player", FALSE);
// PreferenceScreen: Shorts - Shorts player components // PreferenceScreen: Shorts - Shorts player components
public static final BooleanSetting HIDE_SHORTS_CHANNEL_BAR = new BooleanSetting("revanced_hide_shorts_channel_bar", FALSE); public static final BooleanSetting HIDE_SHORTS_CHANNEL_BAR = new BooleanSetting("revanced_hide_shorts_channel_bar", FALSE);

View File

@ -21,6 +21,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import kotlin.collections.listOf
internal val bottomSheetMenuListBuilderFingerprint = legacyFingerprint( internal val bottomSheetMenuListBuilderFingerprint = legacyFingerprint(
name = "bottomSheetMenuListBuilderFingerprint", name = "bottomSheetMenuListBuilderFingerprint",
@ -187,3 +188,40 @@ internal val shortsFullscreenFeatureFingerprint = legacyFingerprint(
literals = listOf(FULLSCREEN_FEATURE_FLAG), literals = listOf(FULLSCREEN_FEATURE_FLAG),
) )
// Pre 19.25
internal val shortsPlaybackIntentLegacyFingerprint = legacyFingerprint(
name = "shortsPlaybackIntentLegacyFingerprint",
returnType = "V",
parameters = listOf(
"L",
"Ljava/util/Map;",
"J",
"Ljava/lang/String;",
"Z",
"Ljava/util/Map;"
),
strings = listOf(
// None of these strings are unique.
"com.google.android.apps.youtube.app.endpoint.flags",
"ReelWatchFragmentArgs",
"reels_fragment_descriptor"
)
)
internal val shortsPlaybackIntentFingerprint = legacyFingerprint(
name = "shortsPlaybackIntentFingerprint",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
returnType = "V",
parameters = listOf(
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;",
"Ljava/util/Map;",
"J",
"Ljava/lang/String;"
),
strings = listOf(
// None of these strings are unique.
"com.google.android.apps.youtube.app.endpoint.flags",
"ReelWatchFragmentArgs",
"reels_fragment_descriptor"
)
)

View File

@ -62,6 +62,9 @@ import app.revanced.patches.youtube.utils.toolbar.hookToolBar
import app.revanced.patches.youtube.utils.toolbar.toolBarHookPatch import app.revanced.patches.youtube.utils.toolbar.toolBarHookPatch
import app.revanced.patches.youtube.video.information.hookShortsVideoInformation import app.revanced.patches.youtube.video.information.hookShortsVideoInformation
import app.revanced.patches.youtube.video.information.videoInformationPatch import app.revanced.patches.youtube.video.information.videoInformationPatch
import app.revanced.patches.youtube.video.playbackstart.PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.video.playbackstart.playbackStartDescriptorPatch
import app.revanced.patches.youtube.video.playbackstart.playbackStartVideoIdReference
import app.revanced.patches.youtube.video.videoid.hookPlayerResponseVideoId import app.revanced.patches.youtube.video.videoid.hookPlayerResponseVideoId
import app.revanced.patches.youtube.video.videoid.videoIdPatch import app.revanced.patches.youtube.video.videoid.videoIdPatch
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
@ -569,6 +572,8 @@ val shortsComponentPatch = bytecodePatch(
shortsToolBarPatch, shortsToolBarPatch,
lithoFilterPatch, lithoFilterPatch,
navigationBarHookPatch,
playbackStartDescriptorPatch,
playerTypeHookPatch, playerTypeHookPatch,
sharedResourceIdPatch, sharedResourceIdPatch,
textComponentPatch, textComponentPatch,
@ -874,6 +879,47 @@ val shortsComponentPatch = bytecodePatch(
// endregion // endregion
// region patch for open Shorts in regular player
fun extensionInstructions(playbackStartRegister: Int, freeRegister: Int) =
"""
invoke-virtual { v$playbackStartRegister }, $playbackStartVideoIdReference
move-result-object v$freeRegister
invoke-static { v$freeRegister }, $SHORTS_CLASS_DESCRIPTOR->openShortInRegularPlayer(Ljava/lang/String;)Z
move-result v$freeRegister
if-eqz v$freeRegister, :disabled
return-void
:disabled
nop
"""
if (!is_19_25_or_greater) {
shortsPlaybackIntentLegacyFingerprint.methodOrThrow().apply {
val index = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.returnType == PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR
}
val freeRegister = getInstruction<FiveRegisterInstruction>(index).registerC
val playbackStartRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA
addInstructionsWithLabels(
index + 2,
extensionInstructions(playbackStartRegister, freeRegister)
)
}
return@execute
}
shortsPlaybackIntentFingerprint.methodOrThrow().addInstructionsWithLabels(
0,
"""
move-object/from16 v0, p1
${extensionInstructions(0, 1)}
"""
)
// endregion
addLithoFilter(BUTTON_FILTER_CLASS_DESCRIPTOR) addLithoFilter(BUTTON_FILTER_CLASS_DESCRIPTOR)
addLithoFilter(SHELF_FILTER_CLASS_DESCRIPTOR) addLithoFilter(SHELF_FILTER_CLASS_DESCRIPTOR)
addLithoFilter(RETURN_YOUTUBE_CHANNEL_NAME_FILTER_CLASS_DESCRIPTOR) addLithoFilter(RETURN_YOUTUBE_CHANNEL_NAME_FILTER_CLASS_DESCRIPTOR)

View File

@ -1318,6 +1318,9 @@ Info:
<string name="revanced_change_shorts_repeat_state_entry_default">Default</string> <string name="revanced_change_shorts_repeat_state_entry_default">Default</string>
<string name="revanced_change_shorts_repeat_state_entry_pause">Pause</string> <string name="revanced_change_shorts_repeat_state_entry_pause">Pause</string>
<string name="revanced_change_shorts_repeat_state_entry_repeat">Repeat</string> <string name="revanced_change_shorts_repeat_state_entry_repeat">Repeat</string>
<string name="revanced_open_shorts_in_regular_player_title">Open Shorts in regular player</string>
<string name="revanced_open_shorts_in_regular_player_summary_on">Open Shorts in the regular player.</string>
<string name="revanced_open_shorts_in_regular_player_summary_off">Do not open Shorts in the regular player.</string>
<!-- PreferenceScreen: Shorts, PreferenceCategory: Shorts, PreferenceScreen: Shorts player --> <!-- PreferenceScreen: Shorts, PreferenceCategory: Shorts, PreferenceScreen: Shorts player -->
<string name="revanced_preference_screen_shorts_player_title">Shorts player</string> <string name="revanced_preference_screen_shorts_player_title">Shorts player</string>

View File

@ -653,7 +653,8 @@
<ListPreference android:entries="@array/revanced_change_shorts_repeat_state_entries" android:title="@string/revanced_change_shorts_background_repeat_state_title" android:key="revanced_change_shorts_background_repeat_state" android:entryValues="@array/revanced_change_shorts_repeat_state_entry_values" />SETTINGS: SHORTS_REPEAT_STATE_BACKGROUND --> <ListPreference android:entries="@array/revanced_change_shorts_repeat_state_entries" android:title="@string/revanced_change_shorts_background_repeat_state_title" android:key="revanced_change_shorts_background_repeat_state" android:entryValues="@array/revanced_change_shorts_repeat_state_entry_values" />SETTINGS: SHORTS_REPEAT_STATE_BACKGROUND -->
<!-- SETTINGS: SHORTS_COMPONENTS <!-- SETTINGS: SHORTS_COMPONENTS
<ListPreference android:entries="@array/revanced_change_shorts_repeat_state_entries" android:title="@string/revanced_change_shorts_repeat_state_title" android:key="revanced_change_shorts_repeat_state" android:entryValues="@array/revanced_change_shorts_repeat_state_entry_values" />SETTINGS: SHORTS_COMPONENTS --> <ListPreference android:entries="@array/revanced_change_shorts_repeat_state_entries" android:title="@string/revanced_change_shorts_repeat_state_title" android:key="revanced_change_shorts_repeat_state" android:entryValues="@array/revanced_change_shorts_repeat_state_entry_values" />
<SwitchPreference android:title="@string/revanced_open_shorts_in_regular_player_title" android:key="revanced_open_shorts_in_regular_player" android:summaryOn="@string/revanced_open_shorts_in_regular_player_summary_on" android:summaryOff="@string/revanced_open_shorts_in_regular_player_summary_off" />SETTINGS: SHORTS_COMPONENTS -->
<!-- PREFERENCE_SCREEN: SHORTS <!-- PREFERENCE_SCREEN: SHORTS
</PreferenceScreen>PREFERENCE_SCREEN: SHORTS --> </PreferenceScreen>PREFERENCE_SCREEN: SHORTS -->