diff --git a/content.js b/content.js index 9a1d7b2..14b3bcc 100644 --- a/content.js +++ b/content.js @@ -13,8 +13,7 @@ let generatedIdCounter = 0; let hudDirty = false; let lastHudSignature = ""; const STORAGE_KEY = "memberOnlyHidden"; -const MAX_GLOBAL_ITEMS = 200; -const MAX_PER_CHANNEL = 20; +const DEFAULT_MAX_ARCHIVE = 500; let persistTimer = null; /* ---------------- CSS injection ---------------- */ @@ -259,7 +258,7 @@ function process(root = document) { const channelUrl = channelInfo.url || ""; const channelKey = channelInfo.key; const id = getOrCreateVideoId(video, url); - const stableId = getStableId(video, url); + const stableId = getStableId(video, url, id); video.setAttribute(`data-${DATA_PREFIX}-member-only`, "true"); if (channelKey) video.setAttribute(`data-${DATA_PREFIX}-channel`, channelKey); @@ -374,11 +373,11 @@ function getOrCreateVideoId(video, url) { return generated; } -function getStableId(video, url) { +function getStableId(video, url, fallbackId) { const dataId = video.getAttribute("data-video-id"); if (dataId) return dataId; if (url) return url; - return ""; + return fallbackId || ""; } // Read the channel key from DOM or fallback to text. @@ -490,6 +489,9 @@ function updateHudDot() { } function updateSharedIndex(meta, hidden) { + if (!meta.stableId) { + meta.stableId = meta.url || meta.id || ""; + } if (!meta.stableId) return; if (hidden) { sharedIndex.set(meta.stableId, { @@ -500,7 +502,8 @@ function updateSharedIndex(meta, hidden) { title: meta.title, url: meta.url, thumb: meta.thumb, - hidden: true + hidden: true, + lastSeen: Date.now() }); } else { sharedIndex.delete(meta.stableId); @@ -518,20 +521,16 @@ function schedulePersistSharedIndex() { function persistSharedIndex() { const items = Array.from(sharedIndex.values()); - items.sort((a, b) => a.id.localeCompare(b.id)); - - const perChannelCounts = new Map(); - const pruned = []; - for (const item of items) { - const key = item.channelKey || item.channelLabel || "(unknown)"; - const count = perChannelCounts.get(key) || 0; - if (count >= MAX_PER_CHANNEL) continue; - if (pruned.length >= MAX_GLOBAL_ITEMS) break; - perChannelCounts.set(key, count + 1); - pruned.push(item); - } - - chrome.storage.local.set({ [STORAGE_KEY]: pruned }); + items.sort((a, b) => (b.lastSeen || 0) - (a.lastSeen || 0)); + chrome.storage.local.get({ maxArchive: DEFAULT_MAX_ARCHIVE }, data => { + const maxArchive = Number(data.maxArchive); + const max = Number.isFinite(maxArchive) ? maxArchive : DEFAULT_MAX_ARCHIVE; + if (max < 0) { + chrome.storage.local.set({ [STORAGE_KEY]: items }); + return; + } + chrome.storage.local.set({ [STORAGE_KEY]: items.slice(0, max) }); + }); } function loadStoredIndex() { diff --git a/popup.css b/popup.css index 7c5c068..9892643 100644 --- a/popup.css +++ b/popup.css @@ -1,19 +1,58 @@ /* Base layout */ body { - font-family: "Trebuchet MS", "Verdana", sans-serif; - min-width: 260px; + font-family: "Oswald", "Impact", "Franklin Gothic Medium", sans-serif; + min-width: 460px; margin: 0; - padding: 12px; - background: linear-gradient(180deg, #f7f3e8, #efe6d2); - color: #2b2014; + padding: 0; + background: radial-gradient(circle at 20% 10%, #2b2b2b, #151515 60%); + color: #f5efe6; } -/* Title */ -h3 { - margin: 0 0 10px; - letter-spacing: 0.4px; +.scroll { + max-height: 640px; + overflow-y: auto; + padding-bottom: 14px; +} + +:root { + --orange: #e35b14; + --orange-strong: #ff7a1a; + --dark: #171717; + --dark-2: #1f1f1f; + --cream: #f5efe6; + --muted: #c7b8a4; +} + +.topbar { + display: flex; + align-items: center; + gap: 10px; + padding: 12px 14px; + background: linear-gradient(90deg, var(--orange), #c9490e); + border-bottom: 2px solid #b2410e; +} + +.logo { + width: 24px; + height: 24px; + border-radius: 6px; + background: radial-gradient(circle, #fff1d6, #ffb256); + box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.25); +} + +.title-wrap h3 { + margin: 0; + letter-spacing: 1px; text-transform: uppercase; - font-size: 13px; + font-size: 16px; + color: #fff8ee; +} + +.subtitle { + font-size: 10px; + letter-spacing: 0.8px; + text-transform: uppercase; + color: #2a1506; } .subtext { @@ -32,47 +71,110 @@ h3 { display: flex; gap: 6px; align-items: center; - margin-bottom: 8px; + margin: 8px 12px 0; +} + +details.section { + margin: 10px 10px 0; + padding: 6px 6px 10px; + border-radius: 10px; + background: rgba(15, 15, 15, 0.55); + border: 1px solid #2a2a2a; +} + +details.section > summary { + list-style: none; + cursor: pointer; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.6px; + font-size: 11px; + color: #ffd8b0; + padding: 6px 6px 2px; +} + +details.section > summary::-webkit-details-marker { + display: none; +} + +details.section > summary::before { + content: "▸"; + margin-right: 6px; + color: #ffb26a; +} + +details.section[open] > summary::before { + content: "▾"; +} + +/* Description */ +.subtext { + margin: 10px 12px 0; + font-size: 11px; + line-height: 1.35; + color: var(--muted); + font-family: "Verdana", sans-serif; +} + +.subtext.subtext-debug { + margin-top: 6px; } .row.settings { justify-content: space-between; + margin-top: 10px; +} + +.hint { + margin: 6px 12px 0; + font-size: 11px; + color: #ffb26a; + font-family: "Verdana", sans-serif; + min-height: 14px; } /* Inputs */ input { flex: 1; - padding: 6px 8px; - border: 1px solid #cdbf9e; - border-radius: 6px; - background: #fffaf0; + padding: 8px 10px; + border: 1px solid #393939; + border-radius: 8px; + background: var(--dark-2); font-size: 12px; + color: var(--cream); + outline: none; } /* Buttons */ button { - padding: 6px 10px; - border: 1px solid #b2985b; - border-radius: 6px; - background: #d9c18c; - color: #2b2014; + padding: 8px 12px; + border: 1px solid #9b3b0c; + border-radius: 8px; + background: var(--orange); + color: #1f0f06; font-size: 12px; cursor: pointer; + transition: transform 0.08s ease, filter 0.15s ease; } button.ghost { background: transparent; - border-color: #cdbf9e; + border-color: #4a3a2a; + color: var(--cream); } button:hover { - filter: brightness(0.95); + filter: brightness(1.05); +} + +button:active { + transform: translateY(1px); } /* List */ ul { padding-left: 0; - margin: 0; + margin: 10px 12px 12px; list-style: none; } @@ -81,18 +183,20 @@ li { display: flex; justify-content: space-between; margin: 4px 0; - padding: 6px 8px; - background: #fffaf0; - border: 1px solid #e2d7be; - border-radius: 6px; + padding: 8px 10px; + background: #232323; + border: 1px solid #3a2c22; + border-radius: 8px; font-size: 12px; + color: var(--cream); } li button { padding: 2px 8px; border-radius: 999px; - border-color: #c95a3a; - background: #f2a285; + border-color: #9b3b0c; + background: var(--orange-strong); + color: #1f0f06; } /* Debug toggle row */ @@ -101,4 +205,24 @@ li button { gap: 6px; align-items: center; font-size: 12px; + color: var(--cream); +} + +.section.explain { + margin: 10px 12px 12px; + padding: 10px 12px; + border-radius: 10px; + background: #1c1c1c; + border: 1px solid #2b2b2b; + font-family: "Verdana", sans-serif; + font-size: 11px; + color: var(--muted); +} + +.explain-title { + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.6px; + color: #ffb26a; + margin-bottom: 6px; } diff --git a/popup.html b/popup.html index 9acc5ea..fe98ba7 100644 --- a/popup.html +++ b/popup.html @@ -6,36 +6,78 @@
- -- Hide member-only videos by default. Whitelisted creators stay visible. - Add the channel name and its @handle or link. -
++ Hide member-only videos by default. Whitelisted creators stay visible. + Add the channel name and its @handle or link. +
- -- Debug logs will appear in the console only when enabled. -
++ Debug logs will appear in the console only when enabled. +
++ Bottom-right dot: grey means none detected. Orange pulsing means member-only + videos were found. Click it to see the list. +
+ + ++ This tool hides members-only videos you can’t watch. Add creators you + support to the whitelist so their videos stay visible. +
++ The orange dot shows when hidden members-only videos exist. Click it to + see a list of what’s hidden. +
+