A Manifest V3 Chrome extension that:
/shorts/<id> redirected to /watch?v=<id>), Up next (sidebar,
end screen, end cards; playlists stay), autoplay, and optionally comments.
Each is a switch in the popup and applies live.chrome.storage.sync.You can load this build unpacked (below). It is being prepared for an
Unlisted Chrome Web Store release (link-only, not searchable); see
store-listing.md for the listing copy and submission steps.
chrome://extensions.youtube-feed-blocker/, the one containing manifest.json).To update after code changes: return to chrome://extensions and click the
reload icon on the extension card, then refresh YouTube.
manifest.json
src/
background.js MV3 service worker: seeds default settings on install
lib/defaults.js shared constants + default settings
lib/storage.js chrome.storage.sync wrapper
lib/feed-budget.js daily feed time: remaining, peek lengths, budget changes
lib/peek-session.js the running peek, shared by all tabs (storage.session)
content/
hide-shorts.css static Shorts-hiding rules (pre-paint)
overlay.css styles for the injected home-feed panel
shorts-blocker.js Shorts UI removal + /shorts redirect + observer
feed-widgets.js to-do / quote widgets
feed-replacer.js hides the real home grid, injects the panel
watch-page.css Up next / autoplay / comments hiding (class-keyed)
watch-page.js mirrors those settings to <html> classes, turns autoplay off
reason-banner.js "You came for" reminder after a reason peek
peek-timer.js closing countdown chip and the time's up card
popup/ popup UI (hide toggles, peek level, feed mode, widgets, AI instruction)
icons/ placeholder icons
chrome.storage.sync, key settings){
shortsBlocking: true,
hideHomeFeed: true,
hideUpNext: true,
blockAutoplay: true,
hideComments: false,
peekLevel: "pause" | "reason" | "none",
feedMode: "blank" | "widgets" | "ai",
aiInstruction: "",
widgets: { todo: true, quote: true },
dailyBudgetMinutes: 0 | 15 | 30 | 45 | 60 | 90, // 0 = Off
pendingBudget: null | { minutes, requestedOn: "YYYY-MM-DD" }
}
Also stored: feedTimeUsage in chrome.storage.sync ({ date, usedMinutes })
and the running peek in chrome.storage.session (peekSession:
{ endsAt, reason, bannerClosed }).
Unit tests: node test/unit.mjs checks the settings layer (settings, upgrade, daily feed time, peek session, storage errors) in plain Node.
Signed-out smoke test — node test/e2e.mjs loads the extension unpacked into
Playwright’s Chromium and checks Shorts removal, the /shorts redirect, all
three feed modes, SPA re-mount, and live settings propagation (59 assertions).
Reuses the Playwright build the Playwright MCP already installed; screenshots to
test/screenshots/.
Real logged-in QA — Chrome stable disables unpacked extensions under automation, so this route has you drive:
C:\Users\aasim\yfb-chrome-test-profile\launch-for-qa.bat (starts Chrome
with a debug port on an isolated, non-synced profile).chrome://extensions → Developer mode → Load unpacked → this folder;
sign into YouTube.node test/live-qa-cdp.mjs — attaches over CDP, checks feed replacement on a
real populated feed, Shorts removal in the sidebar and search results, the
redirect, and blocking on/off. test/live-qa-cdp-followup.mjs adds
dark-mode screenshots and reloads the extension first.The isolated profile keeps its own copy of your session — it is deliberately outside OneDrive and must never be committed.