Enhance HUD functionality: implement shared index for cross-tab data management and improve persistence of member-only video visibility
This commit is contained in:
parent
ab931e1264
commit
cb062589fa
101
content.js
101
content.js
@ -4,6 +4,7 @@ let whitelistHandles = [];
|
||||
let debugEnabled = false;
|
||||
// In-memory index of known member-only videos.
|
||||
const memberOnlyIndex = new Map(); // id -> { channelKey, hidden }
|
||||
const sharedIndex = new Map(); // stableId -> meta for cross-tab HUD
|
||||
// Data-* attribute prefix for DOM tags.
|
||||
const DATA_PREFIX = "chipperfluff-nobs"; // nobs = "no-bs" (member-only videos)
|
||||
const HUD_DOT_ID = `${DATA_PREFIX}-hud-dot`;
|
||||
@ -11,6 +12,10 @@ const HUD_PANEL_ID = `${DATA_PREFIX}-hud-panel`;
|
||||
let generatedIdCounter = 0;
|
||||
let hudDirty = false;
|
||||
let lastHudSignature = "";
|
||||
const STORAGE_KEY = "memberOnlyHidden";
|
||||
const MAX_GLOBAL_ITEMS = 200;
|
||||
const MAX_PER_CHANNEL = 20;
|
||||
let persistTimer = null;
|
||||
|
||||
/* ---------------- CSS injection ---------------- */
|
||||
|
||||
@ -209,9 +214,20 @@ function loadSettings() {
|
||||
}
|
||||
|
||||
loadSettings();
|
||||
loadStoredIndex();
|
||||
|
||||
// Reload settings if popup changes them.
|
||||
chrome.storage.onChanged.addListener(loadSettings);
|
||||
// Reload settings or shared HUD data if storage changes.
|
||||
chrome.storage.onChanged.addListener(changes => {
|
||||
if (changes[STORAGE_KEY]) {
|
||||
const items = changes[STORAGE_KEY].newValue || [];
|
||||
sharedIndex.clear();
|
||||
items.forEach(item => sharedIndex.set(item.id, item));
|
||||
updateHudDot();
|
||||
}
|
||||
if (changes.whitelist || changes.debug) {
|
||||
loadSettings();
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------------- detection logic ---------------- */
|
||||
|
||||
@ -243,6 +259,7 @@ function process(root = document) {
|
||||
const channelUrl = channelInfo.url || "";
|
||||
const channelKey = channelInfo.key;
|
||||
const id = getOrCreateVideoId(video, url);
|
||||
const stableId = getStableId(video, url);
|
||||
|
||||
video.setAttribute(`data-${DATA_PREFIX}-member-only`, "true");
|
||||
if (channelKey) video.setAttribute(`data-${DATA_PREFIX}-channel`, channelKey);
|
||||
@ -255,6 +272,7 @@ function process(root = document) {
|
||||
channelKey,
|
||||
channelLabel: channel,
|
||||
channelUrl,
|
||||
stableId,
|
||||
hidden: false,
|
||||
title,
|
||||
url,
|
||||
@ -280,6 +298,7 @@ function process(root = document) {
|
||||
const meta = memberOnlyIndex.get(id);
|
||||
if (!meta.hidden) hudDirty = true;
|
||||
meta.hidden = true;
|
||||
updateSharedIndex(meta, true);
|
||||
}
|
||||
} else {
|
||||
video.removeAttribute(`data-${DATA_PREFIX}-hidden`);
|
||||
@ -287,6 +306,7 @@ function process(root = document) {
|
||||
const meta = memberOnlyIndex.get(id);
|
||||
if (meta.hidden) hudDirty = true;
|
||||
meta.hidden = false;
|
||||
updateSharedIndex(meta, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -310,10 +330,12 @@ function updateKnownVisibility() {
|
||||
video.removeAttribute(`data-${DATA_PREFIX}-hidden`);
|
||||
if (meta.hidden) hudDirty = true;
|
||||
meta.hidden = false;
|
||||
updateSharedIndex(meta, false);
|
||||
} else {
|
||||
video.setAttribute(`data-${DATA_PREFIX}-hidden`, "true");
|
||||
if (!meta.hidden) hudDirty = true;
|
||||
meta.hidden = true;
|
||||
updateSharedIndex(meta, true);
|
||||
}
|
||||
}
|
||||
updateHudDot();
|
||||
@ -352,6 +374,13 @@ function getOrCreateVideoId(video, url) {
|
||||
return generated;
|
||||
}
|
||||
|
||||
function getStableId(video, url) {
|
||||
const dataId = video.getAttribute("data-video-id");
|
||||
if (dataId) return dataId;
|
||||
if (url) return url;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Read the channel key from DOM or fallback to text.
|
||||
function getChannelKey(video) {
|
||||
const stored = video.getAttribute(`data-${DATA_PREFIX}-channel`);
|
||||
@ -441,12 +470,8 @@ function ensureHudDot() {
|
||||
function updateHudDot() {
|
||||
const dot = ensureHudDot();
|
||||
const panel = document.getElementById(HUD_PANEL_ID);
|
||||
let total = 0;
|
||||
let hidden = 0;
|
||||
for (const meta of memberOnlyIndex.values()) {
|
||||
total += 1;
|
||||
if (meta.hidden) hidden += 1;
|
||||
}
|
||||
const total = sharedIndex.size;
|
||||
const hidden = total;
|
||||
const signature = `${total}:${hidden}`;
|
||||
dot.title = `Member-only videos: ${total} (${hidden} hidden)`;
|
||||
dot.setAttribute(
|
||||
@ -464,6 +489,59 @@ function updateHudDot() {
|
||||
}
|
||||
}
|
||||
|
||||
function updateSharedIndex(meta, hidden) {
|
||||
if (!meta.stableId) return;
|
||||
if (hidden) {
|
||||
sharedIndex.set(meta.stableId, {
|
||||
id: meta.stableId,
|
||||
channelKey: meta.channelKey,
|
||||
channelLabel: meta.channelLabel,
|
||||
channelUrl: meta.channelUrl,
|
||||
title: meta.title,
|
||||
url: meta.url,
|
||||
thumb: meta.thumb,
|
||||
hidden: true
|
||||
});
|
||||
} else {
|
||||
sharedIndex.delete(meta.stableId);
|
||||
}
|
||||
schedulePersistSharedIndex();
|
||||
}
|
||||
|
||||
function schedulePersistSharedIndex() {
|
||||
if (persistTimer) return;
|
||||
persistTimer = setTimeout(() => {
|
||||
persistTimer = null;
|
||||
persistSharedIndex();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
function loadStoredIndex() {
|
||||
chrome.storage.local.get({ [STORAGE_KEY]: [] }, data => {
|
||||
sharedIndex.clear();
|
||||
data[STORAGE_KEY].forEach(item => sharedIndex.set(item.id, item));
|
||||
updateHudDot();
|
||||
});
|
||||
}
|
||||
|
||||
function renderHudPanel(panel) {
|
||||
panel.innerHTML = "";
|
||||
const title = document.createElement("div");
|
||||
@ -472,9 +550,12 @@ function renderHudPanel(panel) {
|
||||
panel.appendChild(title);
|
||||
|
||||
const groups = new Map();
|
||||
for (const meta of memberOnlyIndex.values()) {
|
||||
for (const meta of sharedIndex.values()) {
|
||||
if (!meta.hidden) continue;
|
||||
const key = meta.channelKey || getChannelKeyFromData(meta.channelLabel, meta.channelUrl) || "(unknown)";
|
||||
const key =
|
||||
meta.channelKey ||
|
||||
getChannelKeyFromData(meta.channelLabel, meta.channelUrl) ||
|
||||
"(unknown)";
|
||||
const list = groups.get(key) || [];
|
||||
list.push(meta);
|
||||
groups.set(key, list);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user