feat(YouTube - Hide Shorts components): Selectively hide Shorts for home / subscription / search (#592)

This commit is contained in:
LisoUseInAIKyrios 2024-03-27 17:44:01 +04:00 committed by GitHub
parent 4ae7d5b178
commit 1ee99aa6f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 89 additions and 56 deletions

View File

@ -112,6 +112,37 @@ final class KeywordContentFilter extends Filter {
private volatile ByteTrieSearch bufferSearch; 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. * Change first letter of the first word to use title case.
*/ */
@ -224,15 +255,6 @@ final class KeywordContentFilter extends Filter {
addPathCallbacks(startsWithFilter, containsFilter); 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 @Override
public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
@ -240,34 +262,7 @@ final class KeywordContentFilter extends Filter {
return false; return false;
} }
if (NavigationBar.isSearchBarActive()) { if (!hideKeywordSettingIsActive()) return false;
// 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;
}
// Field is intentionally compared using reference equality. // Field is intentionally compared using reference equality.
if (Settings.HIDE_KEYWORD_CONTENT_PHRASES.get() != lastKeywordPhrasesParsed) { if (Settings.HIDE_KEYWORD_CONTENT_PHRASES.get() != lastKeywordPhrasesParsed) {
@ -281,4 +276,5 @@ final class KeywordContentFilter extends Filter {
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
} }
} }

View File

@ -1,15 +1,19 @@
package app.revanced.integrations.youtube.patches.components; package app.revanced.integrations.youtube.patches.components;
import static app.revanced.integrations.shared.Utils.hideViewUnderCondition;
import android.os.Build; import android.os.Build;
import android.view.View; import android.view.View;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import app.revanced.integrations.youtube.settings.Settings;
import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar; import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;
import static app.revanced.integrations.shared.Utils.hideViewBy1dpUnderCondition; import app.revanced.integrations.shared.Utils;
import static app.revanced.integrations.shared.Utils.hideViewUnderCondition; import app.revanced.integrations.youtube.settings.Settings;
import app.revanced.integrations.youtube.shared.NavigationBar;
import app.revanced.integrations.youtube.shared.PlayerType;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@RequiresApi(api = Build.VERSION_CODES.N) @RequiresApi(api = Build.VERSION_CODES.N)
@ -35,8 +39,10 @@ public final class ShortsFilter extends Filter {
private final ByteArrayFilterGroupList videoActionButtonGroupList = new ByteArrayFilterGroupList(); private final ByteArrayFilterGroupList videoActionButtonGroupList = new ByteArrayFilterGroupList();
public ShortsFilter() { public ShortsFilter() {
// Identifier components.
var shorts = new StringFilterGroup( var shorts = new StringFilterGroup(
Settings.HIDE_SHORTS, null, // Setting is based on navigation state.
"shorts_shelf", "shorts_shelf",
"inline_shorts", "inline_shorts",
"shorts_grid", "shorts_grid",
@ -46,7 +52,7 @@ public final class ShortsFilter extends Filter {
// Feed Shorts shelf header. // Feed Shorts shelf header.
// Use a different filter group for this pattern, as it requires an additional check after matching. // Use a different filter group for this pattern, as it requires an additional check after matching.
shelfHeader = new StringFilterGroup( shelfHeader = new StringFilterGroup(
Settings.HIDE_SHORTS, null,
"shelf_header.eml" "shelf_header.eml"
); );
@ -58,14 +64,14 @@ public final class ShortsFilter extends Filter {
addIdentifierCallbacks(shorts, shelfHeader, thanksButton); addIdentifierCallbacks(shorts, shelfHeader, thanksButton);
// Path components.
// Shorts that appear in the feed/search when the device is using tablet layout. // Shorts that appear in the feed/search when the device is using tablet layout.
shortsCompactFeedVideoPath = new StringFilterGroup(Settings.HIDE_SHORTS, shortsCompactFeedVideoPath = new StringFilterGroup(null, "compact_video.eml");
"compact_video.eml");
// Filter out items that use the 'frame0' thumbnail. // Filter out items that use the 'frame0' thumbnail.
// This is a valid thumbnail for both regular videos and Shorts, // This is a valid thumbnail for both regular videos and Shorts,
// but it appears these thumbnails are used only for Shorts. // but it appears these thumbnails are used only for Shorts.
shortsCompactFeedVideoBuffer = new ByteArrayFilterGroup(Settings.HIDE_SHORTS, shortsCompactFeedVideoBuffer = new ByteArrayFilterGroup(null, "/frame0.jpg");
"/frame0.jpg");
// Shorts player components. // Shorts player components.
joinButton = new StringFilterGroup( joinButton = new StringFilterGroup(
@ -174,7 +180,8 @@ public final class ShortsFilter extends Filter {
) return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); ) return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
if (matchedGroup == shortsCompactFeedVideoPath) { 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 super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
} }
return false; return false;
@ -195,22 +202,41 @@ public final class ShortsFilter extends Filter {
) { ) {
if (path.startsWith(REEL_CHANNEL_BAR_PATH)) return super.isFiltered( if (path.startsWith(REEL_CHANNEL_BAR_PATH)) return super.isFiltered(
identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex
); ); // else, return false.
} }
return false; return false;
} else if (matchedGroup == shelfHeader) { } else {
// Because the header is used in watch history and possibly other places, check for the index, // Feed/search path components.
// which is 0 when the shelf header is used for Shorts. if (matchedGroup == shelfHeader) {
if (contentIndex != 0) return false; // 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. // Super class handles logging.
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); 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) { 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. // region Hide the buttons in older versions of YouTube. New versions use Litho.

View File

@ -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_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_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_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_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_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", "", 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_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_MEDICAL_PANELS = new BooleanSetting("revanced_hide_medical_panels", TRUE);
public static final BooleanSetting HIDE_MIX_PLAYLISTS = new BooleanSetting("revanced_hide_mix_playlists", TRUE); public static final BooleanSetting HIDE_MIX_PLAYLISTS = new BooleanSetting("revanced_hide_mix_playlists", TRUE);
@ -141,7 +141,10 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_TRANSCIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE); public static final BooleanSetting HIDE_TRANSCIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", TRUE);
// Shorts // 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_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 = 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); public static final BooleanSetting HIDE_SHORTS_SUBSCRIBE_BUTTON_PAUSED = new BooleanSetting("revanced_hide_shorts_subscribe_button_paused", FALSE);
@ -362,6 +365,14 @@ public class Settings extends BaseSettings {
// Remove any previously saved announcement consumer (a random generated string). // Remove any previously saved announcement consumer (a random generated string).
Setting.preferences.saveString("revanced_announcement_consumer", null); 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 // endregion
} }