Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat(YouTube - Hide Shorts components): Add option to hide Shorts in watch history #4214

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff
if (matchedGroup == suggestedAction) {
// Skip searching the buffer if all suggested actions are set to hidden.
// This has a secondary effect of hiding all new un-identified actions
// under the assumption that the user wants all actions hidden.
// under the assumption that the user wants all suggestions hidden.
if (isEverySuggestedActionFilterEnabled()) {
return super.isFiltered(path, identifier, protobufBufferArray, matchedGroup, contentType, contentIndex);
}
Expand All @@ -324,19 +324,22 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff
}

private static boolean shouldHideShortsFeedItems() {
// Known issue if hide home is on but at least one other hide is off:
//
// Shorts suggestions will load in the background if a video is opened and
// immediately minimized before any suggestions are loaded.
// In this state the player type will show minimized, which cannot
// distinguish between Shorts suggestions loading in the player and between
// scrolling thru search/home/subscription tabs while a player is minimized.
final boolean hideHome = Settings.HIDE_SHORTS_HOME.get();
final boolean hideSubscriptions = Settings.HIDE_SHORTS_SUBSCRIPTIONS.get();
final boolean hideSearch = Settings.HIDE_SHORTS_SEARCH.get();
final boolean hideHistory = Settings.HIDE_SHORTS_HISTORY.get();

if (hideHome && hideSubscriptions && hideSearch) {
// Shorts suggestions can load in the background if a video is opened and
// then immediately minimized before any suggestions are loaded.
// In this state the player type will show minimized, which makes it not possible to
// distinguish between Shorts suggestions loading in the player and between
// scrolling thru search/home/subscription tabs while a player is minimized.
//
// To avoid this situation for users that never want to show Shorts (all hide Shorts options are enabled)
// then hide all Shorts everywhere including the Library history and Library playlists.
if (!hideHome && !hideSubscriptions && !hideSearch && !hideHistory) {
return false;
}
if (hideHome && hideSubscriptions && hideSearch && hideHistory) {
return true;
}

Expand All @@ -352,24 +355,29 @@ private static boolean shouldHideShortsFeedItems() {
}

// Avoid checking navigation button status if all other Shorts should show.
if (!hideHome && !hideSubscriptions) {
if (!hideHome && !hideSubscriptions && !hideHistory) {
return false;
}

// Check navigation absolutely last since the check may block this thread.
NavigationButton selectedNavButton = NavigationButton.getSelectedNavigationButton();
if (selectedNavButton == null) {
return hideHome; // Unknown tab, treat the same as home.
}
if (selectedNavButton == NavigationButton.HOME) {
return hideHome;
}
if (selectedNavButton == NavigationButton.SUBSCRIPTIONS) {
return hideSubscriptions;
}
// User must be in the library tab. Don't hide the history or any playlists here.
return false;

return switch (selectedNavButton) {
case HOME -> hideHome;
case SUBSCRIPTIONS -> hideSubscriptions;
case LIBRARY -> hideHistory;
default -> false;
};
}

/**
* Injection point. Only used if patching older than 19.03.
* This hook may be obsolete even for old versions
* as they now use a litho layout like newer versions.
*/
public static void hideShortsShelf(final View shortsShelfView) {
if (shouldHideShortsFeedItems()) {
Utils.hideViewByLayoutParams(shortsShelfView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_SHORTS_FULL_VIDEO_LINK_LABEL = new BooleanSetting("revanced_hide_shorts_full_video_link_label", FALSE);
public static final BooleanSetting HIDE_SHORTS_GREEN_SCREEN_BUTTON = new BooleanSetting("revanced_hide_shorts_green_screen_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_HASHTAG_BUTTON = new BooleanSetting("revanced_hide_shorts_hashtag_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_HISTORY = new BooleanSetting("revanced_hide_shorts_history", FALSE);
public static final BooleanSetting HIDE_SHORTS_HOME = new BooleanSetting("revanced_hide_shorts_home", FALSE);
public static final BooleanSetting HIDE_SHORTS_INFO_PANEL = new BooleanSetting("revanced_hide_shorts_info_panel", TRUE);
public static final BooleanSetting HIDE_SHORTS_JOIN_BUTTON = new BooleanSetting("revanced_hide_shorts_join_button", TRUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,21 @@ public static boolean isSearchBarActive() {
* How long to wait for the set nav button latch to be released. Maximum wait time must
* be as small as possible while still allowing enough time for the nav bar to update.
*
* YT calls it's back button handlers out of order,
* and litho starts filtering before the navigation bar is updated.
* YT calls it's back button handlers out of order, and litho starts filtering before the
* navigation bar is updated. Fixing this situation and not needlessly waiting requires
* somehow detecting if a back button key/gesture will not change the active tab.
*
* Fixing this situation and not needlessly waiting requires somehow
* detecting if a back button key-press will cause a tab change.
* On average the time between pressing the back button and the first litho event is
* about 10-20ms. Waiting up to 75-150ms should be enough time to handle normal use cases
* and not be noticeable, since YT typically takes 100-200ms (or more) to update the view.
*
* Typically after pressing the back button, the time between the first litho event and
* when the nav button is updated is about 10-20ms. Using 50-100ms here should be enough time
* and not noticeable, since YT typically takes 100-200ms (or more) to update the view anyways.
* This delay is only noticeable when the device back button/gesture will not
* change the current navigation tab, such as backing out of the watch history.
*
* This issue can also be avoided on a patch by patch basis, by avoiding calls to
* {@link NavigationButton#getSelectedNavigationButton()} unless absolutely necessary.
*/
private static final long LATCH_AWAIT_TIMEOUT_MILLISECONDS = 75;
private static final long LATCH_AWAIT_TIMEOUT_MILLISECONDS = 120;

/**
* Used as a workaround to fix the issue of YT calling back button handlers out of order.
Expand Down Expand Up @@ -113,7 +114,8 @@ private static void waitForNavButtonLatchIfNeeded() {
// The latch is released from the main thread, and waiting from the main thread will always timeout.
// This situation has only been observed when navigating out of a submenu and not changing tabs.
// and for that use case the nav bar does not change so it's safe to return here.
Logger.printDebug(() -> "Cannot block main thread waiting for nav button. Using last known navbar button status.");
Logger.printDebug(() -> "Cannot block main thread waiting for nav button. " +
"Using last known navbar button status.");
return;
}

Expand All @@ -131,7 +133,9 @@ private static void waitForNavButtonLatchIfNeeded() {
Logger.printDebug(() -> "Latch wait timed out");

} catch (InterruptedException ex) {
Logger.printException(() -> "Latch wait interrupted failure", ex); // Will never happen.
// Calling YouTube thread was interrupted.
Logger.printException(() -> "Latch wait interrupted", ex);
Thread.currentThread().interrupt(); // Restore interrupt status flag.
}
}

Expand Down Expand Up @@ -283,8 +287,8 @@ public enum NavigationButton {
*
* All code calling this method should handle a null return value.
*
* <b>Due to issues with how YT processes physical back button events,
* this patch uses workarounds that can cause this method to take up to 75ms
* <b>Due to issues with how YT processes physical back button/gesture events,
* this patch uses workarounds that can cause this method to take up to 120ms
* if the device back button was recently pressed.</b>
*
* @return The active navigation tab.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private val hideShortsComponentsResourcePatch = resourcePatch {
SwitchPreference("revanced_hide_shorts_home"),
SwitchPreference("revanced_hide_shorts_subscriptions"),
SwitchPreference("revanced_hide_shorts_search"),
SwitchPreference("revanced_hide_shorts_history"),

PreferenceScreenPreference(
key = "revanced_shorts_player_screen",
Expand Down
15 changes: 9 additions & 6 deletions patches/src/main/resources/addresources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -632,15 +632,18 @@ Note: Enabling this also forcibly hides video ads"</string>
<string name="revanced_shorts_player_screen_summary">Hide or show components in the Shorts player</string>
<!-- 'home' should be translated using the same localized wording YouTube displays for the home tab. -->
<string name="revanced_hide_shorts_home_title">Hide Shorts in home feed</string>
<string name="revanced_hide_shorts_home_summary_on">Shorts in home feed are hidden</string>
<string name="revanced_hide_shorts_home_summary_off">Shorts in home feed are shown</string>
<string name="revanced_hide_shorts_home_summary_on">Home feed and related videos are hidden</string>
<string name="revanced_hide_shorts_home_summary_off">Home feed and related videos are shown</string>
<!-- 'subscription' should be translated using the same localized wording YouTube displays for the subscription tab. -->
<string name="revanced_hide_shorts_subscriptions_title">Hide Shorts in subscription feed</string>
<string name="revanced_hide_shorts_subscriptions_summary_on">Shorts in subscription feed are hidden</string>
<string name="revanced_hide_shorts_subscriptions_summary_off">Shorts in subscription feed are shown</string>
<string name="revanced_hide_shorts_subscriptions_summary_on">Hidden in subscription feed</string>
<string name="revanced_hide_shorts_subscriptions_summary_off">Shown in subscription feed</string>
<string name="revanced_hide_shorts_search_title">Hide Shorts in search results</string>
<string name="revanced_hide_shorts_search_summary_on">Shorts in search results are hidden</string>
<string name="revanced_hide_shorts_search_summary_off">Shorts in search results are shown</string>
<string name="revanced_hide_shorts_search_summary_on">Hidden in search results</string>
<string name="revanced_hide_shorts_search_summary_off">Shown in search results</string>
<string name="revanced_hide_shorts_history_title">Hide Shorts in watch history</string>
<string name="revanced_hide_shorts_history_summary_on">Hidden in watch history</string>
<string name="revanced_hide_shorts_history_summary_off">Shown in watch history</string>
<!-- 'join' should be translated using the same localized wording YouTube displays for the button. -->
<string name="revanced_hide_shorts_join_button_title">Hide join button</string>
<string name="revanced_hide_shorts_join_button_summary_on">Join button is hidden</string>
Expand Down
Loading