Skip to content

Commit

Permalink
feat(YouTube - Hide Shorts components): Selectively hide Shorts for h…
Browse files Browse the repository at this point in the history
…ome / subscription / search (#592)
  • Loading branch information
LisoUseInAIKyrios committed Mar 27, 2024
1 parent 4ae7d5b commit 1ee99aa
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,37 @@ final class KeywordContentFilter extends Filter {

private volatile ByteTrieSearch bufferSearch;

private static void logNavigationState(String state) {
// Enable locally to debug filtering. Default off to reduce log spam.
final boolean LOG_NAVIGATION_STATE = false;
// noinspection ConstantValue
if (LOG_NAVIGATION_STATE) {
Logger.printDebug(() -> "Navigation state: " + state);
}
}

private static boolean hideKeywordSettingIsActive() {
if (NavigationBar.isSearchBarActive()) {
// Must check first. Search bar can be active with almost any tab.
logNavigationState("Search");
return Settings.HIDE_KEYWORD_CONTENT_SEARCH.get();
} else if (PlayerType.getCurrent().isMaximizedOrFullscreen()) {
// For now, consider the under video results the same as the home feed.
logNavigationState("Player active");
return Settings.HIDE_KEYWORD_CONTENT_HOME.get();
} else if (NavigationButton.HOME.isSelected()) {
logNavigationState("Home tab");
return Settings.HIDE_KEYWORD_CONTENT_HOME.get();
} else if (NavigationButton.SUBSCRIPTIONS.isSelected()) {
logNavigationState("Subscription tab");
return Settings.HIDE_SUBSCRIPTIONS_BUTTON.get();
} else {
// User is in the Library or Notifications tab.
logNavigationState("Ignored tab");
}
return false;
}

/**
* Change first letter of the first word to use title case.
*/
Expand Down Expand Up @@ -224,50 +255,14 @@ public KeywordContentFilter() {
addPathCallbacks(startsWithFilter, containsFilter);
}

private static void logNavigationState(String state) {
// Enable locally to debug filtering. Default off to reduce log spam.
final boolean LOG_NAVIGATION_STATE = false;
// noinspection ConstantValue
if (LOG_NAVIGATION_STATE) {
Logger.printDebug(() -> "Navigation state: " + state);
}
}

@Override
public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
if (contentIndex != 0 && matchedGroup == startsWithFilter) {
return false;
}

if (NavigationBar.isSearchBarActive()) {
// Search bar can be active with almost any tab active.
if (!Settings.HIDE_KEYWORD_CONTENT_SEARCH.get()) {
return false;
}
logNavigationState("Search");
} else if (PlayerType.getCurrent().isMaximizedOrFullscreen()) {
// For now, consider the under video results the same as the home feed.
if (!Settings.HIDE_KEYWORD_CONTENT_HOME.get()) {
return false;
}
logNavigationState("Player active");
} else if (NavigationButton.HOME.isSelected()) {
// Could use a Switch statement, but there is only 2 tabs of interest.
if (!Settings.HIDE_KEYWORD_CONTENT_HOME.get()) {
return false;
}
logNavigationState("Home tab");
} else if (NavigationButton.SUBSCRIPTIONS.isSelected()) {
if (!Settings.HIDE_SUBSCRIPTIONS_BUTTON.get()) {
return false;
}
logNavigationState("Subscription tab");
} else {
// User is in the Library or Notifications tab.
logNavigationState("Ignored tab");
return false;
}
if (!hideKeywordSettingIsActive()) return false;

// Field is intentionally compared using reference equality.
if (Settings.HIDE_KEYWORD_CONTENT_PHRASES.get() != lastKeywordPhrasesParsed) {
Expand All @@ -281,4 +276,5 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto

return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package app.revanced.integrations.youtube.patches.components;

import static app.revanced.integrations.shared.Utils.hideViewUnderCondition;

import android.os.Build;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import app.revanced.integrations.youtube.settings.Settings;
import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;

import static app.revanced.integrations.shared.Utils.hideViewBy1dpUnderCondition;
import static app.revanced.integrations.shared.Utils.hideViewUnderCondition;
import app.revanced.integrations.shared.Utils;
import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.shared.NavigationBar;
import app.revanced.integrations.youtube.shared.PlayerType;

@SuppressWarnings("unused")
@RequiresApi(api = Build.VERSION_CODES.N)
Expand All @@ -35,8 +39,10 @@ public final class ShortsFilter extends Filter {
private final ByteArrayFilterGroupList videoActionButtonGroupList = new ByteArrayFilterGroupList();

public ShortsFilter() {
// Identifier components.

var shorts = new StringFilterGroup(
Settings.HIDE_SHORTS,
null, // Setting is based on navigation state.
"shorts_shelf",
"inline_shorts",
"shorts_grid",
Expand All @@ -46,7 +52,7 @@ public ShortsFilter() {
// Feed Shorts shelf header.
// Use a different filter group for this pattern, as it requires an additional check after matching.
shelfHeader = new StringFilterGroup(
Settings.HIDE_SHORTS,
null,
"shelf_header.eml"
);

Expand All @@ -58,14 +64,14 @@ public ShortsFilter() {

addIdentifierCallbacks(shorts, shelfHeader, thanksButton);

// Path components.

// Shorts that appear in the feed/search when the device is using tablet layout.
shortsCompactFeedVideoPath = new StringFilterGroup(Settings.HIDE_SHORTS,
"compact_video.eml");
shortsCompactFeedVideoPath = new StringFilterGroup(null, "compact_video.eml");
// Filter out items that use the 'frame0' thumbnail.
// This is a valid thumbnail for both regular videos and Shorts,
// but it appears these thumbnails are used only for Shorts.
shortsCompactFeedVideoBuffer = new ByteArrayFilterGroup(Settings.HIDE_SHORTS,
"/frame0.jpg");
shortsCompactFeedVideoBuffer = new ByteArrayFilterGroup(null, "/frame0.jpg");

// Shorts player components.
joinButton = new StringFilterGroup(
Expand Down Expand Up @@ -174,7 +180,8 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff
) return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);

if (matchedGroup == shortsCompactFeedVideoPath) {
if (contentIndex == 0 && shortsCompactFeedVideoBuffer.check(protobufBufferArray).isFiltered()) {
if (shouldHideShortsFeedItems() && contentIndex == 0
&& shortsCompactFeedVideoBuffer.check(protobufBufferArray).isFiltered()) {
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
}
return false;
Expand All @@ -195,22 +202,41 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff
) {
if (path.startsWith(REEL_CHANNEL_BAR_PATH)) return super.isFiltered(
identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex
);
); // else, return false.
}

return false;
} else if (matchedGroup == shelfHeader) {
// Because the header is used in watch history and possibly other places, check for the index,
// which is 0 when the shelf header is used for Shorts.
if (contentIndex != 0) return false;
} else {
// Feed/search path components.
if (matchedGroup == shelfHeader) {
// Because the header is used in watch history and possibly other places, check for the index,
// which is 0 when the shelf header is used for Shorts.
if (contentIndex != 0) return false;
}

if (!shouldHideShortsFeedItems()) return false;
}

// Super class handles logging.
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
}

private static boolean shouldHideShortsFeedItems() {
if (NavigationBar.isSearchBarActive()) { // Must check search first.
return Settings.HIDE_SHORTS_SEARCH.get();
} else if (PlayerType.getCurrent().isMaximizedOrFullscreen()
|| NavigationBar.NavigationButton.HOME.isSelected()) {
return Settings.HIDE_SHORTS_HOME.get();
} else if (NavigationBar.NavigationButton.SUBSCRIPTIONS.isSelected()) {
return Settings.HIDE_SHORTS_SUBSCRIPTIONS.get();
}
return false;
}

public static void hideShortsShelf(final View shortsShelfView) {
hideViewBy1dpUnderCondition(Settings.HIDE_SHORTS, shortsShelfView);
if (shouldHideShortsFeedItems()) {
Utils.hideViewByLayoutParams(shortsShelfView);
}
}

// region Hide the buttons in older versions of YouTube. New versions use Litho.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_IMAGE_SHELF = new BooleanSetting("revanced_hide_image_shelf", TRUE);
public static final BooleanSetting HIDE_INFO_CARDS = new BooleanSetting("revanced_hide_info_cards", TRUE);
public static final BooleanSetting HIDE_JOIN_MEMBERSHIP_BUTTON = new BooleanSetting("revanced_hide_join_membership_button", TRUE);
public static final BooleanSetting HIDE_KEYWORD_CONTENT_SEARCH = new BooleanSetting("revanced_hide_keyword_content_search", FALSE);
public static final BooleanSetting HIDE_KEYWORD_CONTENT_HOME = new BooleanSetting("revanced_hide_keyword_content_home", FALSE);
public static final BooleanSetting HIDE_KEYWORD_CONTENT_SUBSCRIPTIONS = new BooleanSetting("revanced_hide_keyword_content_subscriptions", FALSE);
public static final BooleanSetting HIDE_KEYWORD_CONTENT_SEARCH = new BooleanSetting("revanced_hide_keyword_content_search", FALSE);
public static final StringSetting HIDE_KEYWORD_CONTENT_PHRASES = new StringSetting("revanced_hide_keyword_content_phrases", "",
parentsAny(HIDE_KEYWORD_CONTENT_SEARCH, HIDE_KEYWORD_CONTENT_HOME, HIDE_KEYWORD_CONTENT_SUBSCRIPTIONS));
parentsAny(HIDE_KEYWORD_CONTENT_HOME, HIDE_KEYWORD_CONTENT_SUBSCRIPTIONS, HIDE_KEYWORD_CONTENT_SEARCH));
public static final BooleanSetting HIDE_LOAD_MORE_BUTTON = new BooleanSetting("revanced_hide_load_more_button", TRUE, true);
public static final BooleanSetting HIDE_MEDICAL_PANELS = new BooleanSetting("revanced_hide_medical_panels", TRUE);
public static final BooleanSetting HIDE_MIX_PLAYLISTS = new BooleanSetting("revanced_hide_mix_playlists", TRUE);
Expand Down Expand Up @@ -141,7 +141,10 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_TRANSCIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE);

// Shorts
public static final BooleanSetting HIDE_SHORTS = new BooleanSetting("revanced_hide_shorts", FALSE, true);
@Deprecated public static final BooleanSetting DEPRECATED_HIDE_SHORTS = new BooleanSetting("revanced_hide_shorts", FALSE);
public static final BooleanSetting HIDE_SHORTS_HOME = new BooleanSetting("revanced_hide_shorts_home", FALSE);
public static final BooleanSetting HIDE_SHORTS_SUBSCRIPTIONS = new BooleanSetting("revanced_hide_shorts_subscriptions", FALSE);
public static final BooleanSetting HIDE_SHORTS_SEARCH = new BooleanSetting("revanced_hide_shorts_search", FALSE);
public static final BooleanSetting HIDE_SHORTS_JOIN_BUTTON = new BooleanSetting("revanced_hide_shorts_join_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_SUBSCRIBE_BUTTON = new BooleanSetting("revanced_hide_shorts_subscribe_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_SUBSCRIBE_BUTTON_PAUSED = new BooleanSetting("revanced_hide_shorts_subscribe_button_paused", FALSE);
Expand Down Expand Up @@ -362,6 +365,14 @@ public class Settings extends BaseSettings {
// Remove any previously saved announcement consumer (a random generated string).
Setting.preferences.saveString("revanced_announcement_consumer", null);

// Shorts
if (DEPRECATED_HIDE_SHORTS.get()) {
Logger.printInfo(() -> "Migrating hide Shorts setting");
DEPRECATED_HIDE_SHORTS.resetToDefault();
HIDE_SHORTS_HOME.save(true);
HIDE_SHORTS_SUBSCRIPTIONS.save(true);
HIDE_SHORTS_SEARCH.save(true);
}

// endregion
}
Expand Down

0 comments on commit 1ee99aa

Please sign in to comment.