From dae7bfed8b373fc9e3809406675cb7d2c1234581 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 16 Jan 2026 02:43:03 +0000 Subject: [PATCH] Fix trusted mute hide threshold logic on home feed - Ensure 'decorateVideoModeration' in 'js/app.js' respects the feed policy bypass logic (simulating server-side behavior). - Pass 'feedContext' (feedName, feedVariant) to 'decorateVideoModeration' from 'refreshVisibleModerationUi' and 'handleModerationSettingsChange'. - This prevents videos on the Home feed from being strictly hidden (removed from DOM) when the "Hide after trusted mutes" threshold is met, ensuring they remain visible but blurred as expected by the bypass policy. - Verified with reproduction script that 'hidden' becomes false and 'blurThumbnail' remains true on Home feed context. --- js/app.js | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/js/app.js b/js/app.js index 7bd88fba..73bcc993 100644 --- a/js/app.js +++ b/js/app.js @@ -3659,11 +3659,15 @@ class Application { async handleModerationSettingsChange({ settings, skipRefresh = false } = {}) { const normalized = this.normalizeModerationSettings(settings); this.moderationSettings = normalized; + const feedContext = { + feedName: this.feedName || "", + feedVariant: this.feedVariant || "", + }; if (this.videosMap instanceof Map) { for (const video of this.videosMap.values()) { if (video && typeof video === "object") { - this.decorateVideoModeration(video); + this.decorateVideoModeration(video, feedContext); } } } @@ -3677,7 +3681,7 @@ class Application { continue; } if (card.video && typeof card.video === "object") { - this.decorateVideoModeration(card.video); + this.decorateVideoModeration(card.video, feedContext); } try { card.refreshModerationUi(); @@ -3693,13 +3697,13 @@ class Application { if (this.videoListView && Array.isArray(this.videoListView.currentVideos)) { for (const video of this.videoListView.currentVideos) { if (video && typeof video === "object") { - this.decorateVideoModeration(video); + this.decorateVideoModeration(video, feedContext); } } } if (this.currentVideo && typeof this.currentVideo === "object") { - this.decorateVideoModeration(this.currentVideo); + this.decorateVideoModeration(this.currentVideo, feedContext); } if (!skipRefresh) { @@ -3718,6 +3722,10 @@ class Application { refreshVisibleModerationUi({ reason } = {}) { const context = reason ? ` after ${reason}` : ""; + const feedContext = { + feedName: this.feedName || "", + feedVariant: this.feedVariant || "", + }; const redecorateVideo = (video) => { if (!video || typeof video !== "object") { @@ -3725,7 +3733,7 @@ class Application { } try { - this.decorateVideoModeration(video); + this.decorateVideoModeration(video, feedContext); } catch (error) { devLogger.warn( `[Application] Failed to decorate video moderation${context}:`, @@ -6031,7 +6039,7 @@ class Application { return { ...this.moderationSettings }; } - decorateVideoModeration(video) { + decorateVideoModeration(video, feedContext = {}) { if (!video || typeof video !== "object") { return video; } @@ -6226,7 +6234,23 @@ class Application { } : null; + const FEED_HIDE_BYPASS_NAMES = new Set(["home", "recent"]); + const normalizedFeedName = + typeof feedContext?.feedName === "string" ? feedContext.feedName.trim().toLowerCase() : ""; + const normalizedFeedVariant = + typeof feedContext?.feedVariant === "string" + ? feedContext.feedVariant.trim().toLowerCase() + : ""; + const feedPolicyBypass = + (normalizedFeedName && FEED_HIDE_BYPASS_NAMES.has(normalizedFeedName)) || + (normalizedFeedVariant && FEED_HIDE_BYPASS_NAMES.has(normalizedFeedVariant)); + let hideBypass = hideTriggered ? existingHideBypass : ""; + + if (hideTriggered && !hideBypass && feedPolicyBypass) { + hideBypass = "feed-policy"; + } + const computedHidden = hideTriggered && !hideBypass; const overrideEntry = getModerationOverride(video.id);